Создание сообщений WCF с несколькими пространствами имен
-
06-07-2019 - |
Вопрос
Я пытаюсь создать реализацию WSTransfer (я понимаю, что Roman Kiss уже написал ее для WCF, но на самом деле она не соответствует спецификациям)
В итоге я отказался от контрактов с данными в служебных контактах, потому что WSTransfer слабо связан;таким образом, каждое сообщение create выглядит как Message Create (запрос сообщения).
Это работает нормально, и все прекрасно, пока не придет время отправлять ответ.
Проблема, с которой я столкнулся, заключается в том, как строится ответ WSTransfer.Взяв create в качестве примера, ответ выглядит следующим образом
<wxf:ResourceCreated>
<wsa:Address>....</wsa:Address>
<wsa:ReferenceProperties>
<xxx:MyID>....</xxx:MyId>
</wsa:ReferenceProperties>
</wxf:ResourceCreated>
Как вы можете видеть, в ответном сообщении есть 3 различных пространства имен XML.
Теперь это достаточно просто, когда кто-то вовлечен;вы можете (даже если вы не раскрываете его) создать контракт с данными, установить значения и запустить его обратно
Message response = Message.CreateMessage(request.Version,
"http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse",
resourceCreatedMessage);
Однако проблема возникает при настройке различных пространств имен для дочерних элементов в ответе;похоже, что datacontracts WCF этого не делают.Даже используя
[MessageBodyMember(Namespace="....")]
поскольку отдельные элементы в классе response, по-видимому, не вносят никаких изменений, все становится частью пространства имен, указанного для класса contract.
Итак, как мне применить разные пространства имен к отдельным элементам в сообщении WCF;либо через контракт, либо через какой-то другой джиговый покер?
Решение 2
Итак, следим за ответом джезелла;проблема с использованием XmlSerialization при создании сообщения вручную заключается в том, что дочерние элементы корневого каталога искажают имена своих элементов.Это происходит потому, что, несмотря на то, что операционный контракт помечен как [XmlSerializerFormat], при создании сообщения вручную используется DataContractSerializer.
Вы не можете передать XmlSerializer в Message.createMessage() потому что для этого требуется XmlObjectSerializer, которым XmlSerializer не является.
Итак, ответ, по-видимому, заключается в написании класса-оболочки для XmlSerializer, который имеет XmlObjectSerializer в качестве базового класса (вот пример) и передайте это в;вместе с классом хранения вашего сообщения.
К сожалению, это недостаточно умно для настройки префиксов в XML;таким образом, в итоге вы получаете такие сообщения, как
<ResourceCreated xmlns="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing/">http://localhost:8731/Design_Time_Addresses/AddTests/WSTransfer/</Address>
<ReferenceType xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing/"></ReferenceType>
Но все это равнозначно.
Другие советы
В таком случае, когда вам нужен точный контроль над выводом XML, вы должны использовать XmlSerializer вместо сериализации DataContract или MessageContract. Вот дополнительная информация о том, как это сделать: