С пользовательским WSDL и ссылочной схемой, почему возвращаемый Xml из моего метода SOAP сериализован из объектов правильно?
После прочтения этой статьи:
Улучшение взаимодействия веб-сервисов с дизайном сообщений XML
Я решил попробовать импортировать нашу существующую схему разработки сообщений в WSDL для нашей новой службы SOAP.
Это все в VS2008 и.NET 3.5, Altova XMLSpy 2009 использовалась для разработки схемы и wsdl.
Итак, я сделал следующее:
- Написать Custom WSDL, импортируя нашу спецификацию интерфейса XSD.
- Сгенерируйте код заглушки сервера, используя WSDL.EXE
- Включить XSD в проект веб-службы
- Используйте Linq To Xsd для создания строго типизированных оболочек XDocument, которые мы используем
- Вручную отредактируйте сгенерированный код заглушки, чтобы удалить избыточные автоматически сгенерированные классы-оболочки
- Вручную отредактируйте код заглушки, чтобы сопоставить типы в WSDL с созданными оболочками Linq2Xsd.
- Отключить генерацию WSDL и явно ссылаться на пользовательский WSDL с помощью
WebServiceBindingAttribute
- Создайте испытательный стенд для выигрышных форм, используя обычные веб-ссылки
Хорошо, вот проблема:
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>
Спасибо за прочтение,
Джеймс.