Поделиться через


Модуль форматирования и селектор операции

В примере QueryStringFormatter показано, как точки расширяемости Windows Communication Foundation (WCF) можно использовать для разрешения данных сообщений в другом формате, отличном от ожидаемого WCF. По умолчанию методы форматирования WCF ожидают, что параметры метода будут включены в soap:body элемент. В этом образце показано, как реализовать пользовательский модуль форматирования операций, который анализирует параметры из строки HTTP-запроса GET и вызывает методы с использованием этих данных.

Пример основан на начале работы, который реализует ICalculator контракт службы. Он показывает, каким образом можно изменить сообщения Add, Subtract, Multiply и Divide, чтобы они использовали HTTP-запросы GET в качестве запросов клиента серверу и HTTP-запросы POST с сообщениями POX в качестве ответов сервера клиенту.

Для этого в образце имеются следующие элементы.

  • Класс QueryStringFormatter, который реализует интерфейсы IClientMessageFormatter и IDispatchMessageFormatter для клиента и сервера соответственно и обрабатывает данные в строке запроса.

  • Класс UriOperationSelector, который реализует интерфейс IDispatchOperationSelector на сервере для выполнения диспетчеризации операций в зависимости от имени операции в запросе GET.

  • Поведение конечной точки EnableHttpGetRequestsBehavior (и соответствующая конфигурация), которое добавляет в среду выполнения селектор нужной операции.

  • Показано, как включить в среду выполнения новый модуль форматирования операций.

  • В этом образце служба и клиент являются консольными приложениями (EXE).

Примечание.

Процедура настройки и инструкции по построению для данного образца приведены в конце этого раздела.

Основные понятия

QueryStringFormatter — Средство форматирования операций — это компонент в WCF, отвечающий за преобразование сообщения в массив объектов параметров и массив объектов параметров в сообщение. Эта задача выполняется на клиенте с помощью интерфейса IClientMessageFormatter и на сервере с помощью интерфейса IDispatchMessageFormatter. Эти интерфейсы позволяют пользователям получать сообщения запросов и ответов из методов Serialize и Deserialize.

В этом образце класс QueryStringFormatter реализует оба эти интерфейса и реализуется на стороне клиента и сервера.

Запрос:

  • В этом образце класс TypeConverter используется для преобразования параметров в сообщении запроса в строки и обратно. Если объект для определенного типа TypeConverter недоступен, модуль форматирования в этом образце создает исключение.

  • В методе IClientMessageFormatter.SerializeRequest на стороне клиента модуль форматирования создает код URI для соответствующего адреса назначения и добавляет имя операции в качестве суффикса. Это имя используется для перенаправления на соответствующую операцию на сервере. После этого массив объектов параметров сериализуется в строку запроса кода URI с использованием имен и значений параметров, преобразованных классом TypeConverter. Свойства To и Via задаются данному URI. Значение MessageProperties доступно через свойство Properties.

  • В методе IDispatchMessageFormatter.DeserializeRequest на сервере модуль форматирования извлекает код URI Via в свойствах сообщения входящего запроса. Модуль форматирования преобразует пары "имя-значение" в строке запроса URI в имена и значения параметров и подставляет эти имена и значения параметров в массив передаваемых методу параметров. Обратите внимание, что диспетчеризация по операциям уже произошла, поэтому в данном методе суффикс имени операции игнорируется.

Ответ:

  • В этом образце HTTP-метод GET используется только для запросов. Модуль форматирования делегирует отправку ответа исходному модулю форматирования, который бы использовался для создания XML-сообщения. Одна из целей этого образца заключается в том, чтобы показать, как можно реализовать такой делегирующий модуль форматирования.

Класс UriPathSuffixOperationSelector

Интерфейс IDispatchOperationSelector позволяет пользователям реализовывать собственную логику определения операции, которой должно перенаправляться то или иное сообщение.

В этом образце необходимо реализовать на сервере класс UriPathSuffixOperationSelector, чтобы выбирать нужную операцию, поскольку имя операции включается в код URI HTTP-запроса GET, а не в заголовок действия в сообщении. В этом образце разрешены только имена операций, указываемые с учетом регистра.

Метод SelectOperation принимает входящее сообщение и ищет в свойствах сообщения код URI Via. Он извлекает из кода URI суффикс имени операции, ищет во внутренней таблице имя операции, которой следует перенаправить сообщение, и возвращает имя операции.

Класс EnableHttpGetRequestsBehavior

Компонент UriPathSuffixOperationSelector можно настраивать программным образом или с помощью поведения конечной точки. Пример реализует EnableHttpGetRequestsBehavior поведение, указанное в файле конфигурации приложения службы.

На сервере:

Свойству OperationSelector присвоена реализация IDispatchOperationSelector.

По умолчанию WCF использует фильтр адресов точного соответствия. Код URI входящего сообщения содержит суффикс имени операции, за которым следует строка запроса, содержащая данные параметров, поэтому поведение также изменяет фильтр адресов, чтобы он срабатывал по совпадению префикса. Она использует WCFPrefixEndpointAddressMessageFilter для этой цели.

Установка модулей форматирования операций

Поведения операций, которые задают модули форматирования, являются уникальными. Одно такое поведение всегда реализуется по умолчанию для каждой операции, чтобы создать нужный модуль форматирования операции. Однако такие поведения очень похожи на поведения других операций; их невозможно идентифицировать по каким-либо другим атрибутам. Чтобы установить поведение замены, реализация должна искать определенные поведения форматирования, установленные загрузчиком типов WCF по умолчанию, и заменить его или добавить совместимое поведение для выполнения после поведения по умолчанию.

Эти поведения модулей форматирования операций можно задать программным образом перед вызовом CommunicationObject.Open или путем задания поведения операции, которое выполняется после поведения по умолчанию. Однако его невозможно легко настроить с помощью поведения конечной точки (а следовательно с помощью конфигурации), поскольку модель поведений не допускает замены поведения другими поведениями или иного изменения дерева описаний.

На клиенте:

Реализацию IClientMessageFormatter нужно осуществлять таким образом, чтобы этот модуль форматирования мог преобразовывать запросы в HTTP-запросы GET и делегировать создание ответов исходному модулю форматирования. Для этого вызывается вспомогательный метод EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior.

Это необходимо сделать до вызова метода CreateChannel.

void ReplaceFormatterBehavior(OperationDescription operationDescription, EndpointAddress address)
{
    // Remove the DataContract behavior if it is present.
    IOperationBehavior formatterBehavior = operationDescription.Behaviors.Remove<DataContractSerializerOperationBehavior>();
    if (formatterBehavior == null)
    {
        // Remove the XmlSerializer behavior if it is present.
        formatterBehavior = operationDescription.Behaviors.Remove<XmlSerializerOperationBehavior>();
        ...
    }

    // Remember what the innerFormatterBehavior was.
    DelegatingFormatterBehavior delegatingFormatterBehavior = new DelegatingFormatterBehavior(address);
    delegatingFormatterBehavior.InnerFormatterBehavior = formatterBehavior;
   operationDescription.Behaviors.Add(delegatingFormatterBehavior);
}

На сервере:

  • Интерфейс IDispatchMessageFormatter нужно реализовать таким образом, чтобы этот модуль форматирования мог считывать HTTP-запросы GET и делегировать создание ответов исходному модулю форматирования. Это делается путем вызова того же вспомогательного метода EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior, что и для клиента (см. предыдущий пример кода).

  • Это необходимо сделать до вызова метода Open. В этом образце показано, каким образом можно вручную изменить модуль форматирования перед вызовом метода Open. Того же результата можно достичь, создав для класса ServiceHost производный класс, который вызывает EnableHttpGetRequestsBehavior.ReplaceFormatterBehavior перед открытием (примеры см. в документации по размещению).

Взаимодействие с пользователем

На сервере:

  • Серверную реализацию ICalculator изменять не требуется.

  • В файле App.config службы следует задавать пользовательскую привязку POX, которая устанавливает для атрибута messageVersion элемента textMessageEncoding значение None.

    <bindings>
      <customBinding>
        <binding name="poxBinding">
          <textMessageEncoding messageVersion="None" />
          <httpTransport />
        </binding>
      </customBinding>
    </bindings>
    
  • Кроме того, в файле App.config службы необходимо задать пользовательское поведение EnableHttpGetRequestsBehavior, добавив его в раздел расширений поведения.

    <behaviors>
      <endpointBehaviors>
        <behavior name="enableHttpGetRequestsBehavior">
          <enableHttpGetRequests />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    
    <extensions>
      <behaviorExtensions>
        <!-- Enabling HTTP GET requests: Behavior Extension -->
        <add
          name="enableHttpGetRequests"           type="Microsoft.ServiceModel.Samples.EnableHttpGetRequestsBehaviorElement, QueryStringFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
    
  • Перед вызовом метода Open необходимо добавить модули форматирования операций.

На клиенте:

  • Изменять клиентскую реализацию не требуется.

  • В файле App.config клиента следует задать пользовательскую привязку POX, которая устанавливает для атрибута messageVersion элемента textMessageEncoding значение None. Отличие от службы заключается в том, что клиент должен включить ручную адресацию, чтобы можно было изменять исходящий адрес назначения.

    <bindings>
      <customBinding>
        <binding name="poxBinding">
          <textMessageEncoding messageVersion="None" />
          <httpTransport manualAddressing="True" />
        </binding>
      </customBinding>
    </bindings>
    
  • В файле App.config клиента должно быть задано то же пользовательское поведение EnableHttpGetRequestsBehavior, что и на сервере.

  • Перед вызовом метода CreateChannel() необходимо добавить модули форматирования операций.

При выполнении примера запросы и ответы операций отображаются в окне консоли клиента. Все четыре операции (Add, Subtract, Multiply и Divide) должны выполняться успешно.

Настройка, сборка и выполнение образца
  1. Убедитесь, что вы выполнили процедуру однократной установки для примеров Windows Communication Foundation.

  2. Чтобы создать решение, следуйте инструкциям по созданию примеров Windows Communication Foundation.

  3. Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в разделе "Примеры Windows Communication Foundation".