Перенос веб-клиента в WCF; Клиент WCF сериализует имя параметра метода

Я борюсь с миграцией с веб-сервиса / архитектуры веб-клиента на архитектуру 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 и отправил сообщение. Из-за указанного (Ответить-) Действие в 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);

Когда я использую Webclient в коде для отправки сообщения, все работает. Моя проблема, когда я использую клиента 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, но это когда имя моего параметра было zakLk01xml, казалось, содержал магический дубликат тега выше, но без пространства имен. Конечно, вы можете представить, как я схожу с ума от происходящего, прежде чем узнаю, что это было имя параметра!

Теперь я фактически создал Службу 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. Но моя архитектура требует разделяемых библиотек, так что это мне не поможет.

Кто-нибудь может мне помочь, пожалуйста! Я не могу ничего гуглить по этому вопросу...

2 ответа

Предложение: если вы только начинаете работать с WCF, начните с того, что делаете "в духе WCF". Если вы знаете, как это сделать правильно, вы можете начать что-то менять. Прямо сейчас вы не знаете, какая часть вашей проблемы связана с WCF, а какая - просто из-за отсутствия у вас опыта работы с WCF.

Я предлагаю вам начать с нуля, не используя [XmlSerializerFormat], Просто создайте ServiceContract с одним OperationContract, Включите хотя бы один FaultContract так что вы можете увидеть, как это работает.

Создайте клиент WCF с помощью "Добавить ссылку на службу" и убедитесь, что он работает.

Затем создайте проект SOAPUI, используя WSDL из службы WCF (не исходный WSDL). Убедитесь, что это работает.

Тогда вы можете начать менять вещи. Пытаться [XmlSerializerFormat], Попробуйте добавить различные [Xml*] атрибутов. Медленно начинайте менять вещи, пока не увидите, что ломается.

Хорошо, я понял это сам. Я уже создал клиент WCF (Service Reference), который работал, и, внимательно изучив сгенерированный код, я выяснил, что происходит. Это связано с тем, что WCF оборачивает все классы, используемые в DECLARATION методов Webservice (поэтому классы, используемые в свойствах класса method-упомянутых классов, не переносятся). В моем случае тело класса ZAKLk01 обернуто тегами XMLElement, используя имя параметра в качестве XMLElement-name. Чтобы избавиться от этого поведения, я теперь использую классы-оболочки для моих сгенерированных прокси-классов ZAKLk01 и Bv03Bericht, так же как сгенерированные классы делают с моими прокси-классами Service References в моем новом клиенте WCF. Эти классы-оболочки оформлены с помощью MessageContractAttributes.

Чтобы привести пример одного из этих классов-оболочек:

[MessageContract(IsWrapped = false)]
public partial class zakLk01Request
{

    [MessageBodyMember(Namespace = Constants.NamespaceStufZKN, Order = 0)]
    public ZAKLk01 zakLk01;

    public zakLk01Request()
    {
    }

    public zakLk01Request(ZAKLk01 zakLk01)
    {
        this.zakLk01 = zakLk01;
    }
}

Мой метод интерфейса теперь выглядит так:

[OperationContract(Action = Constants.NamespaceStufZKN + "/zakLk01", ReplyAction = Constants.NamespaceStufZKN + "/Bv03Bericht")]
[FaultContract(typeof(Fo03Bericht), Namespace = Constants.NamespaceStuf)]
zakLk01Response zakLk01(zakLk01Request zakLk01);

Гораздо чище без тегов XMLElement, функция которых (генерирует правильный xml) теперь заменена классами-обертками.

Причина, по которой я мог получить неупакованный xml, заключалась в том, что мой пользовательский messageinspector содержал некоторый код, предназначенный для приема неупакованных xml-сообщений без необходимости добавлять теги MessageContract ко всем существующим классам (или создавать множество классов-оболочек) (где-то гуглил), что он сделал просто отлично. Фрагмент кода:

MessageDescription.Body.WrapperName = null;

Но получение упакованных сообщений, которые были отправлены моим (первым) клиентом WCF, который все еще упаковывал классы, не сработало, конечно...

Я до сих пор не понимаю, как работают эти атрибуты Action: если я не предоставлю их, мой сгенерированный wsdl не содержит никакого метода. Ну, пока это не важно, так как я наконец-то смогу двигаться дальше, и в другой раз буду повозиться с атрибутами Action.

Другие вопросы по тегам