Я борюсь с переходом с архитектуры веб-сервиса / веб-клиента на архитектуру WCF. Объект очень сложный, с множеством вложенных xsd и разных пространств имен. Прокси-классы создаются путем добавления веб-ссылки на исходный wsdl с более чем 30 веб-методами и использования xsd.exe для создания отсутствующих объектов SOAPFault. Мой экспериментальный сервис WCF состоит только из 1 веб-метода, который соответствует точному синтаксису одного из исходных методов: 1 объект в качестве параметра, возвращающий 1 другой объект в качестве значения результата. Я создал интерфейс WCF, используя эти прокси-классы, используя атрибуты: XMLSerializerFormat
и ServiceContract
в интерфейсе, OperationContract
в одном методе из оригинального wsdl, указав Action
, ReplyAction
, все с соответствующими пространствами имен. Я создаю входящие клиентские сообщения, используя SoapUI; Я сгенерировал проект из исходных файлов WSDL (в результате чего у проекта SoapUI было более 30 методов) и создал один новый запрос для одного реализованного WebMethod, изменил URL-адрес моего веб-сервиса wcf и отправил сообщение. Из-за указанного действия (Reply-) в OperationContractAttribute
сообщение фактически получено и правильно десериализовано в объект.
Чтобы продвинуться так далеко (40 часов поиска в Google), большое разочарование привело меня к использованию настраиваемой конечной точки, в которой удаляются «завернутые теги» WCF, исправляются пространства имен для вложенных типов, а сгенерированный wsdl get выравнивается. (для лучшей совместимости с другими инструментами, чем MS VisualStudio).
Код интерфейса:
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document, SupportFaults = true)]
[ServiceContract(Namespace = Constants.NamespaceStufZKN)]
public interface IOntvangAsynchroon
{
[OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/zakLk01", Name = "zakLk01")]
[FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)]
Bv03Bericht zakLk01([XmlElement("zakLk01", Namespace = Constants.NamespaceStufZKN)] ZAKLk01 zakLk011);
Когда я использую веб-клиент в коде для отправки сообщения, все работает. Моя проблема, когда я использую клиента WCF. Я использую ChannelFactory<IOntvangAsynchroon>
, чтобы отправить сообщение. Но сгенерированный xml выглядит иначе: он включает имя параметра метода! Мне потребовалось много времени, чтобы понять это, но вот что происходит:
Правильный xml (раздетый мыльный конверт):
<soap:Body>
<zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310">
<stuurgegevens>
<berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode>
<zender xmlns="http://www.egem.nl/StUF/StUF0301">
<applicatie>ONBEKEND</applicatie>
</zender>
</stuurgegevens>
<parameters>
</parameters>
</zakLk01>
</soap:Body>
Плохой xml:
<soap:Body>
<zakLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310">
<zakLk011>
<stuurgegevens>
<berichtcode xmlns="http://www.egem.nl/StUF/StUF0301">Bv01</berichtcode>
<zender xmlns="http://www.egem.nl/StUF/StUF0301">
<applicatie>ONBEKEND</applicatie>
</zender>
</stuurgegevens>
<parameters>
</parameters>
</zakLk011>
</zakLk01>
</soap:Body>
Обратите внимание на элемент zakLk011
? Это имя параметра метода в моем интерфейсе! Так что СЕЙЧАС это zakLk011
, но когда мое имя параметра было zakLk01
, xml, казалось, содержал магический дубликат тега выше, но без пространства имен. Конечно, вы можете представить, как я схожу с ума от происходящего, прежде чем узнаю, что это имя параметра!
Теперь я фактически создал Службу WCF, в которой я больше не могу отправлять сообщения с помощью Клиента WCF. Для ясности: метод вызывается с помощью клиента WCF на моем веб-сервисе, но объект параметра пуст. Поскольку я использую собственную конечную точку для регистрации входящего XML, я вижу, что сообщение получено нормально, но только с неправильным синтаксисом!
код клиента WCF:
ZAKLk01 stufbericht = MessageFactory.CreateZAKLk01();
ChannelFactory<IOntvangAsynchroon> factory = new ChannelFactory<IOntvangAsynchroon>(new BasicHttpBinding(), new EndpointAddress("http://localhost:8193/Roxit/Link/zkn0310"));
factory.Endpoint.Behaviors.Add(new LinkEndpointBehavior());
IOntvangAsynchroon client = factory.CreateChannel();
client.zakLk01(stufbericht);
Я не использую сгенерированный клиент, я просто ссылаюсь на веб-сервис (разделяемые библиотеки), как я привык.
Редактировать: при создании ссылки на службу она создает дублирующиеся классы (не знаю, почему ..). Когда эти дубликаты удаляются, клиент отправляет сообщения с правильным XML. Но моя архитектура требует разделяемых библиотек, поэтому это мне не поможет.
Может кто-нибудь помочь мне? Я не могу ничего гуглить по этому вопросу ...