С пользовательским WSDL и ссылочной схемой почему возвращаемый Xml из моего метода SOAP не сериализуется из объектов правильно? - PullRequest
2 голосов
/ 01 марта 2012

После прочтения этой статьи:

Улучшение взаимодействия веб-сервисов с дизайном сообщений XML

Я решил попробовать импортировать нашу существующую схему разработки сообщений в WSDL для нашей новой службы SOAP.

Это все в VS2008 и .NET 3.5, Altova XMLSpy 2009 использовался для разработки схемы и wsdl.

Итак, я сделал следующее:

  1. Написать пользовательский WSDL, импортируя нашу спецификацию интерфейса XSD.
  2. Создание кода заглушки сервера с использованием WSDL.EXE
  3. Включить XSD в проект веб-службы
  4. Используйте Linq To Xsd для генерации строго типизированных оболочек XDocument, которые мы используем
  5. Вручную отредактируйте сгенерированный код заглушки, чтобы удалить избыточные автоматически сгенерированные классы-оболочки
  6. Вручную отредактируйте код заглушки, чтобы сопоставить типы в WSDL с генерируемыми оболочками Linq2Xsd
  7. Отключить генерацию WSDL и явно ссылаться на пользовательский WSDL с помощью WebServiceBindingAttribute
  8. Создание испытательного стенда выигрышных форм с использованием обычных веб-ссылок

Хорошо, вот проблема:

SOAP-запрос работает отлично, сериализация и десериализация параметров работает. Ответ SOAP в проблеме: сериализация создает неправильно сформированный Xml, а клиентская сериализация просто не работает.

Вот ответ SOAP:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetCameraLocationsTableResponse xmlns="http://blah">
            <GetCameraLocationsTableResponse Version="1.0rc2">
                <Response>
                    <Success>true</Success>
                </Response>
                <CameraLocationsTable/>
            </GetCameraLocationsTableResponse>
        </GetCameraLocationsTableResponse>
    </soap:Body>
</soap:Envelope>

Обратите внимание на вложенные элементы GetCameraLocationsTableResponse, это неправильно. Я подтвердил, что наша оболочка XDocument создает внутренний GetCameraLocationsTableResponse, а что-то во внутренней работе генератора сообщений SOAP добавляет внешний GetCameraLocationsTableResponse Должно быть:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetCameraLocationsTableResponse Version="1.0rc2" xmlns="http://blah">
            <Response>
                <Success>true</Success>
            </Response>
            <CameraLocationsTable/>
        </GetCameraLocationsTableResponse>
    </soap:Body>
</soap:Envelope>

Так что я в замешательстве, код прокси клиента сериализуется правильно, а код прокси сервера - нет. Конечно, это код сервера, с которым я взломал!

Имена были изменены на Blah, чтобы защитить невинных.

Для справки, вот мой отредактированный прокси-код на стороне сервера:

[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.Web.Services.WebServiceBindingAttribute(Name = "Blah", Namespace = "http://Blah", Location = @"http://localhost:57264/wsdl/Blah.wsdl")]
public interface IBlah
{

    [System.Web.Services.WebMethodAttribute()]
    [SoapLogger]
    [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
    [return: System.Xml.Serialization.XmlElementAttribute("GetCameraLocationsTableResponse", Namespace="http://Blah")]
    GetCameraLocationsTableResponse GetCameraLocationsTable([System.Xml.Serialization.XmlElementAttribute(Namespace="http://Blah")] NativeCaseInterfaceDelegateRequest NativeCaseInterfaceDelegateRequest);
}

Вот код, который я написал для реализации вышеуказанного в качестве веб-службы:

[WebService(Namespace = "http://blah")]
public class Blah : WebService, IBlah
{
    #region IBlah Members

    public GetCameraLocationsTableResponse GetCameraLocationsTable(Blah BlahRequest)
    {
        return BlahTools.GetCameraLocationsTable(BlahRequest);
    }

    #endregion
}

Используя переключатель system.diagnostics из здесь Мне удалось извлечь автоматически сгенерированный код сериализации:

    protected override void Serialize(object objectToSerialize, System.Xml.Serialization.XmlSerializationWriter writer) {
        ((XmlSerializationWriter1)writer).Write3_Item((object[])objectToSerialize);
    }

    public void Write3_Item(object[] p) {
        WriteStartDocument();
        TopLevelElement();
        int pLength = p.Length;
        if (pLength > 0) {
            WriteSerializable((System.Xml.Serialization.IXmlSerializable)((global::blah.GetCameraLocationsTableResponse)p[0]), @"GetCameraLocationsTableResponse", @"http://blah", false, true);
        }
    }

Вот пользовательский WSDL

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:sis="http://Blah" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://Blah">
    <wsdl:import namespace="http://Blah" location="Blah.xsd"/>
    <wsdl:message name="BlahRequestMessage">
        <wsdl:part name="in" element="sis:BlahRequest"/>
    </wsdl:message>
    <wsdl:message name="GetCameraLocationsTableResponseMessage">
        <wsdl:part name="out" element="sis:GetCameraLocationsTableResponse"/>
    </wsdl:message>
    <wsdl:portType name="BlahPort">
        <wsdl:operation name="GetCameraLocationsTable">
            <wsdl:input message="sis:BlahRequestMessage"/>
            <wsdl:output message="sis:GetCameraLocationsTableResponseMessage"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="Blah" type="sis:BlahPort">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="GetCameraLocationsTable">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
</wsdl:definitions>

Спасибо за чтение,

Джеймс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...