перенос веб-клиента в WCF; Клиент WCF сериализует имя параметра метода - PullRequest
1 голос
/ 01 июня 2010

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

Может кто-нибудь помочь мне? Я не могу ничего гуглить по этому вопросу ...

Ответы [ 2 ]

0 голосов
/ 02 июня 2010

Хорошо, я понял это сам. Я уже создал работающий клиент 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 ко всем существующим классам (или создавать множество классов-оболочек) (googled) это где-то), что он сделал просто отлично. Фрагмент кода:

MessageDescription.Body.WrapperName = null;

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

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

0 голосов
/ 02 июня 2010

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

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

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

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

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

...