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


Введение разработчика в Windows Communication Foundation 4

Аарон Сконард, Pluralsight

Оригинал: ноябрь 2009 г.

Обновлено до RTM: апрель 2010 г.

Общие сведения

.NET 4 поставляется с некоторыми привлекательными новыми функциями и приветствуем улучшения в области Windows Communication Foundation (WCF). Эти усовершенствования WCF ориентированы в первую очередь на упрощение взаимодействия с разработчиками, предоставление дополнительных сценариев взаимодействия и обеспечение полнофункциональной интеграции с Windows Workflow Foundation (WF) за счет того, что "службы рабочих процессов" движутся вперед.

Хорошей новостью является то, что большинство изменений WCF 4 направлены на упрощение современных распространенных сценариев и создание новых сценариев коммуникации и стилей разработки. В результате перенос существующих решений WCF в .NET 4 будет довольно простым с точки зрения миграции. Затем вы просто решите, какие функции WCF 4 вы хотите использовать в своих решениях. Остальная часть этого документа знакомит вас с каждой из новых функциональных областей WCF 4 и демонстрирует, как они работают.

Новые возможности WCF 4

WCF 4 поставляется с широким спектром конкретных функций, но на рисунке 1 описаны main функциональные области, на которых мы сосредоточимся в работе ниже. Эти функциональные области обобщают большинство новых возможностей WCF 4 и выделяют возможности верхнего уровня, предоставляемые этим выпуском платформы .NET Framework.

Рис. 1. Функциональные области WCF 4

Область функций Описание

Упрощенная конфигурация

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

Обнаружение

Новая платформа поддерживает нерегламентированное и управляемое поведение обнаружения служб, которые соответствуют стандартному протоколу WS-Discovery.

Служба маршрутизации

Новая платформа поддерживает настраиваемую службу маршрутизации, которую можно использовать в решениях WCF. Предоставляет функции для маршрутизации на основе содержимого, моста по протоколам и обработки ошибок.

Улучшения REST

Усовершенствования веб-служб WCFHttp с некоторыми дополнительными функциями и инструментами, упрощающими разработку служб REST.

Службы рабочего процесса

Расширенная поддержка платформы для интеграции WCF с WF для реализации декларативных долго выполняющихся служб рабочих процессов. Эта новая модель программирования предоставляет лучшее, что могут предложить обе платформы (WCF & WF).

Завершив работу с этими main функциональными областями, мы кратко обсудим некоторые из более сложных функций WCF более низкого уровня, которые поставляются с .NET 4, включая улучшенные возможности разрешения типов, поддержку очередей с конкурирующими потребителями ("контекст получения"), поддержку распакованных двоичных данных с помощью кодировщика потока байтов и поддержку высокопроизводительной трассировки на основе ETW.

К тому времени, когда мы закончим, вы увидите, что WCF 4 станет проще в использовании и обеспечивает более встроенную поддержку некоторых из наиболее распространенных современных сценариев и стилей разработки.

Упрощенная конфигурация

Унифицированная модель программирования, предлагаемая WCF в версии 3.x, является одновременно благословением и проклятием. Она упрощает написание логики службы для различных сценариев взаимодействия, но также повышает сложность на стороне конфигурации, так как предоставляет множество различных базовых параметров связи, которые вы вынуждены понять, прежде чем вы сможете приступить к работе.

Реальность такова, что конфигурация WCF обычно становится наиболее дорогостоящей областью использования WCF на практике сегодня, и значительная часть этой сложности приходится на ИТ-специалистов и сотрудников, которые не готовы к работе с ней.

Учитывая эту реальность, при рассмотрении чистой сложности использования WCF 3.x можно сделать вывод о том, что его сложнее использовать, чем его предшественник ASP.NET веб-службы (ASMX). С помощью ASMX вы смогли определить операцию [WebMethod], а среда выполнения автоматически предоставила конфигурацию по умолчанию для базовых коммуникаций. С другой стороны, при переходе на WCF 3.x разработчикам необходимо достаточно знать о различных параметрах конфигурации WCF, чтобы определить хотя бы одну конечную точку. И сложное количество вариантов конфигурации часто отпугивает некоторых разработчиков.

Чтобы сделать общий интерфейс WCF таким же простым, как ASMX, WCF 4 поставляется с новой моделью конфигурации по умолчанию, которая полностью устраняет необходимость в любой конфигурации WCF. Если вы не предоставляете конфигурацию WCF для конкретной службы, среда выполнения WCF 4 автоматически настраивает службу с использованием некоторых стандартных конечных точек и конфигураций привязки и поведения по умолчанию. Это значительно упрощает работу службы WCF, особенно для тех, кто не знаком с различными параметрами конфигурации WCF и рад принять значения по умолчанию, по крайней мере для начала работы.

Конечные точки по умолчанию

В WCF 3.x при попытке разместить службу без настроенных конечных точек экземпляр ServiceHost вызовет исключение, информирующее о том, что необходимо настроить хотя бы одну конечную точку. В WCF 4 это больше не так, так как среда выполнения автоматически добавляет одну или несколько "конечных точек по умолчанию" для вас, тем самым делая службу доступной для использования без какой-либо конфигурации.

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

Чтобы быть точным, реализация AddDefaultEndpoints добавляет одну конечную точку по умолчанию на базовый адрес для каждого контракта службы, реализованного службой. Например, если служба реализует два контракта службы и вы настраиваете узел с одним базовым адресом, AddDefaultEndpoints настроит службу с двумя конечными точками по умолчанию (по одной для каждого контракта службы). Однако если служба реализует два контракта службы и узел настроен с двумя базовыми адресами (один для HTTP и один для TCP), AddDefaultEndpoints настроит службу с четырьмя конечными точками по умолчанию.

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

[ServiceContract]

общедоступный интерфейс IHello

{

    [OperationContract]

    void SayHello(string name);

}

[ServiceContract]

открытый интерфейс IGoodbye

{

    [OperationContract]

    void SayGoodbye(string name);

}

открытый класс GreetingService: служба IHello, IGoodbye // реализует оба контракта.

{

    public void SayHello(string name)

    {

        Console.WriteLine("Hello {0}", имя);

    }

    public void SayGoodbye(string name)

    {

        Console.WriteLine("Goodbye {0}", name);

    }

}

В WCF 4 теперь можно использовать ServiceHost для размещения службы GreetingService без какой-либо конфигурации приложения. При использовании ServiceHost в пользовательских сценариях размещения необходимо указать один или несколько базовых адресов для использования. Ниже показано, как разместить GreetingService в консольном приложении. Опять же можно предположить, что с этой программой не связан app.config файл:

class Program

{

    static void Main(string[] args)

    {

        Узел настроен с двумя базовыми адресами: один для HTTP и один для TCP

        Узел ServiceHost = new ServiceHost(typeof(GreetingService),

            new Uri("https://localhost:8080/greeting"),

            new Uri("net.tcp://localhost:8081/greeting"));

        Узла. Open();

        foreach (ServiceEndpoint se in host. Description.Endpoints)

            Console.WriteLine("A: {0}, B: {1}, C: {2}",

                Se. Адрес, se.Binding.Name, se.Contract.Name);

        Console.WriteLine("Нажмите клавишу <ВВОД> , чтобы остановить службу.");

        Console.ReadLine();

        Узла. Close();

    }

}

В этом примере для ServiceHost настраивается два базовых адреса: один для HTTP и другой для TCP. При запуске этой программы в окне консоли отображаются четыре конечные точки, как показано на рисунке 2. Вы получите два для базового адреса HTTP, по одному на контракт, и два для базового АДРЕСА TCP, опять же по одному для каждого контракта. Все это предоставляется в фоновом режиме экземпляром ServiceHost.

Рис. 2. Конечные точки по умолчанию, отображаемые в окне консоли

Обратите внимание, что WCF выбирает использование BasicHttpBinding для конечных точек HTTP по умолчанию и NetTcpBinding для конечных точек TCP по умолчанию. Я покажу вам, как изменить эти значения по умолчанию в ближайшее время.

Помните, что это поведение конечной точки по умолчанию запускается, только если служба не была настроена с конечными точками. Если изменить консольное приложение, чтобы настроить для службы хотя бы одну конечную точку, вы больше не увидите в выходных данных ни одну из этих конечных точек по умолчанию. Чтобы проиллюстрировать это, я просто добавлю следующую строку кода, которая вызывает AddServiceEndpoint после создания экземпляра ServiceHost:

...

Узел ServiceHost = new ServiceHost(typeof(GreetingService),

    new Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

Узла. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

...

Если запустить консольное приложение с вставленной строкой кода, вы заметите, что в выходных данных теперь отображается только одна конечная точка, настроенная вручную в приведенном выше коде (см. рис. 3).

Рис. 3. Выходные данные консоли после настройки узла с одной конечной точкой

Однако вы всегда можете вызвать AddDefaultEndpoints самостоятельно, если хотите добавить набор конечных точек по умолчанию вместе с собственными. В следующем примере кода показано, как это сделать:

...

Узел ServiceHost = new ServiceHost(typeof(GreetingService),

    new Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

Узла. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

Узла. AddDefaultEndpoints();

...

Если вы снова запустите консольное приложение с этим изменением, вы увидите пять конечных точек в окне консоли — ту, которую я настроил вручную вместе с четырьмя конечными точками по умолчанию (см. рис. 4).

Рис. 4. Выходные данные консоли после вызова AddDefaultEndpoints вручную

Теперь, когда мы разбираемся в алгоритме и механизме добавления конечных точек по умолчанию в службы во время выполнения, следующий вопрос заключается в том, как WCF определяет, какую привязку следует использовать для конкретного адреса?

Сопоставление протоколов по умолчанию

Ответ на этот вопрос прост. WCF определяет сопоставление протоколов по умолчанию между схемами транспортных протоколов (например, http, net.tcp, net.pipe и т. д.) и встроенными привязками WCF. Сопоставление протокола по умолчанию находится в файле .NET 4 machine.config.comments и выглядит следующим образом:

<system.serviceModel>

   <protocolMapping>

      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="" />

      <add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration="/>

      <add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration="/>

      <add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration="/>

   </protocolMapping>

   ...

Эти сопоставления можно переопределить на уровне компьютера, добавив этот раздел в machine.config и изменив сопоставление для каждой схемы протокола. Или если вы хотите переопределить его только в область приложения, можно переопределить этот раздел в файле конфигурации приложения или веб-сайта.

Например, если ваша организация в основном ориентирована на создание служб RESTful с WCF, может быть целесообразно изменить привязку по умолчанию для схемы протокола http на WebHttpBinding. В следующем примере показано, как это сделать в файле конфигурации приложения:

<Конфигурации>

  <system.serviceModel>

    <protocolMapping>

      <add scheme="http" binding="webHttpBinding"/>

    </protocolMapping>

  </system.serviceModel>

</Конфигурации>

Теперь при повторном запуске консольного приложения, показанного ранее с этим app.config, две конечные точки на основе HTTP по умолчанию будут показывать, что они используют WebHttpBinding (см. рис. 5).

Рис. 5. Выходные данные консоли после переопределения сопоставления протокола HTTP по умолчанию

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

Конфигурации привязки по умолчанию

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

В WCF 3.x для этого необходимо определить именованную конфигурацию привязки, которую можно применить к определениям конечных точек с помощью атрибута bindingConfiguration. Механика правильного выполнения этого является громоздкой и подверженной ошибкам.  В следующем файле конфигурации показан типичный пример:

<настройка>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding name="BasicWithMtom" messageEncoding="Mtom"/>

      </basicHttpBinding>

    </Привязки>

    <services>

      <service name="GreetingService">

        <endpoint address="mtom" binding="basicHttpBinding"

                  bindingConfiguration="BasicWithMtom"

                  contract="IHello"/>

      </service>

    </Услуги>

  </system.serviceModel>

</Конфигурации>

В приведенном выше примере конфигурация привязки BasicWithMtom переопределяет значения по умолчанию для BasicHttpBinding, изменяя кодировку сообщения на MTOM. Однако эта конфигурация привязки вступает в силу только при ее применении к определенной конечной точке с помощью атрибута bindingConfiguration. Это шаг, который часто ускользает от разработчиков и сотрудников, что приводит к проблемам с конфигурацией.

В WCF 4 теперь можно определять конфигурации привязки по умолчанию, просто опуская имя конфигурации привязки при определении новой конфигурации. Затем WCF будет использовать конфигурацию по умолчанию для всех конечных точек, использующих привязку, для которых не задана явная конфигурация привязки.

Например, если мы добавим следующий файл app.config в консольное приложение, показанное ранее, две конечные точки HTTP по умолчанию будут использовать эту конфигурацию BasicHttpBinding, которая включает MTOM:

<Конфигурации>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding messageEncoding="Mtom"/><-- обратите внимание, что атрибут name отсутствует>

      </basicHttpBinding>

    </Привязки>

  </system.serviceModel>

</Конфигурации>

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

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

В дополнение к конфигурациям привязки по умолчанию для служб и конечных точек следует учитывать и конфигурацию поведения по умолчанию.

Конфигурации поведения по умолчанию

WCF 4 также позволяет определить конфигурации поведения по умолчанию для служб и конечных точек, что может упростить процесс, если требуется совместно использовать стандартную конфигурацию поведения по умолчанию для всех служб или конечных точек, работающих на компьютере или в решении.

В WCF 3.x необходимо определить именованные конфигурации поведения, которые явно применяются к службам и конечным точкам с помощью атрибута behaviorConfiguration. В WCF 4 можно определить конфигурации поведения по умолчанию, опустив имя в определении конфигурации. Если вы добавите эти поведения по умолчанию в machine.config, они будут применяться ко всем службам или конечным точкам, размещенным на компьютере. Если вы добавите их в app.config, они вступают в силу только в рамках область ведущего приложения. Ниже приведен пример.

<Конфигурации>

  <system.serviceModel>

    <Поведения>

      <serviceBehaviors>

        <поведение><-- заметьте, что атрибут имени отсутствует>

          <serviceMetadata httpGetEnabled="true"/>

        </Поведение>

      </serviceBehaviors>

    </Поведения>

  </system.serviceModel>

</Конфигурации>

В этом примере включаются метаданные службы для любой службы, которая не имеет явной конфигурации поведения. Если мы добавим эту конфигурацию поведения по умолчанию в файл app.config для консольного приложения, показанного ранее, и снова запустите приложение, мы сможем перейти к базовому HTTP-адресу, чтобы получить страницу справки службы и определение WSDL службы (см. рис. 6).

Рис. 6. Просмотр метаданных службы, включенных конфигурацией поведения по умолчанию

Еще одна новая функция в WCF 4 заключается в том, что конфигурации поведения теперь поддерживают модель наследования. Если приложение определяет конфигурацию поведения с тем же именем, которое уже определено в machine.config, конфигурация поведения конкретного приложения будет объединена с конфигурацией на уровне компьютера, добавив любые дополнительные варианты поведения в производную конфигурацию составного поведения.

Стандартные конечные точки

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

На рисунке 7 описаны стандартные конечные точки, поставляемые с WCF 4. Они предоставляют стандартные определения конечных точек для некоторых наиболее распространенных функций WCF 4 и сценариев взаимодействия. Например, в случае конечной точки MEX всегда необходимо указать IMetadataExchange для контракта службы и, скорее всего, выбрать HTTP. Поэтому вместо того, чтобы всегда делать это вручную, WCF предоставляет стандартное определение конечной точки для обмена метданами с именем mexEndpoint, которое легко использовать.

Рис. 7. Стандартные конечные точки в WCF 4

Стандартное имя конечной точки Описание

mexEndpoint

Определяет стандартную конечную точку для MEX, настроенную с помощью IMetadataExchange для контракта службы, mexHttpBinding в качестве привязки по умолчанию (эту привязку можно изменить) и пустой адрес.

dynamicEndpoint

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

discoveryEndpoint

Определяет стандартную конечную точку, предварительно настроенную для операций обнаружения в клиентском приложении. При использовании этой стандартной конечной точки пользователю необходимо указать адрес и привязку.

udpDiscoveryEndpoint

Определяет стандартную конечную точку, предварительно настроенную для операций обнаружения в клиентском приложении с помощью привязки UDP по адресу многоадресной рассылки. Наследуется от DiscoveryEndpoint.

announcementEndpoint

Определяет стандартную конечную точку, предварительно настроенную для функции объявления обнаружения. При использовании этой стандартной конечной точки пользователю необходимо указать адрес и привязку.

udpAnnouncementEndpoint

Определяет стандартную конечную точку, предварительно настроенную для функции объявления через привязку UDP по адресу многоадресной рассылки. Эта конечная точка является производным от announcementEndpoint.

workflowControlEndpoint

Определяет стандартную конечную точку для управления выполнением экземпляров рабочего процесса (создание, выполнение, приостановка, завершение и т. д.).

webHttpEndpoint

Определяет стандартную конечную точку, настроенную с помощью WebHttpBinding и WebHttpBehavior. Используйте для предоставления служб REST.

webScriptEndpoint

Определяет стандартную конечную точку, настроенную с помощью WebHttpBinding и WebScriptEnablingBehavior. Используйте для предоставления служб Ajax.

Вы можете использовать любую из этих стандартных конечных точек в собственных конфигурациях служб, просто ссылаясь на них по имени. Элемент <endpoint> теперь поставляется с атрибутом kind, который можно использовать для указания имени стандартной конечной точки. Например, следующий пример настраивает GreetingService с конечной точкой MEX, используя стандартное определение mexEndpoint:

<настройка>

  <system.serviceModel>

    <services>

      <service name="GreetingService">

        <endpoint kind="basicHttpBinding" contract="IHello"/>

        <endpoint kind="mexEndpoint" address="mex" />

      </service>

    </Услуги>

  </system.serviceModel>

</Конфигурации>

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

При необходимости можно использовать <раздел standardEndpoints> и переопределить конфигурацию конечной точки для стандартной конечной точки. Затем вы можете ссылаться на эту конфигурацию при определении новой <конечной точки> с помощью атрибута endpointConfiguration, как показано ниже:

<Конфигурации>

  <system.serviceModel>

    <services>

      <service name="GreetingService">

        <endpoint binding="basicHttpBinding" contract="IHello"/>

        <endpoint kind="udpDiscoveryEndpoint" endpointConfiguration="D11"/>

      </service>

    </Услуги>

    <standardEndpoints>

      <udpDiscoveryEndpoint>

        <standardEndpoint name="D11" discoveryVersion="WSDiscovery11"/>

      </udpDiscoveryEndpoint>

    </standardEndpoints>

    <Поведения>

      <serviceBehaviors>

        <Поведение>

          <serviceDiscovery/>

          <serviceMetadata httpGetEnabled="true"/>

        </Поведение>

      </serviceBehaviors>

    </Поведения>

  </system.serviceModel>

</Конфигурации>

В этом примере изменяется версия WS-Discovery по умолчанию для стандартной конечной точки с именем "udpDiscoveryEndpoint" (вскоре мы поговорим об обнаружении служб).

Упрощение размещения IIS и ASP.NET

Учитывая эти новые функции для конечных точек по умолчанию, конфигураций привязки по умолчанию и конфигураций поведения по умолчанию, размещение в IIS/ASP.NET значительно упрощается в WCF 4. ASP.NET разработчики, которые привыкли работать со службами ASMX, теперь могут определять службы WCF, которые являются простыми по своей природе.

Фактически проверка, насколько просто следующее определение службы WCF:

<-- HelloWorld.svc -->

<%@ ServiceHost Language="C#" Debug="true" Service="HelloWorldService

    CodeBehind="~/App_Code/HelloWorldService.cs" %>

[ServiceContract]

открытый класс HelloWorldService

{

    [OperationContract]

    public string HelloWorld()

    {

        возврат "hello, world";

    }

}

Это простейшая форма определения службы WCF, так как мы не используем отдельное определение интерфейса для определения контракта службы, и все определяется в одном файле HelloWorld.svc (примечание. Я не рекомендую этот подход, просто отмечая, что можно провести сравнение с ASMX). Это должно быть похоже на типичные службы ASMX, основное отличие заключается в именах атрибутов, используемых в классе службы (например, [WebService] и [WebMethod]). Есть определенно меньше движущихся частей.

С помощью новых функций WCF 4, описанных в предыдущем разделе, теперь вы можете перейти к HelloWorld.svc без дополнительной конфигурации WCF, а логика активации WCF создаст экземпляр ServiceHost в фоновом режиме и настроит его с одной конечной точкой HTTP по умолчанию. Если вы добавили поведение службы по умолчанию в файл machine.config, включающее метаданные службы, вы увидите страницу справки WCF и ссылку на определение WSDL при переходе по адресу HelloWorld.svc (см. рис. 8).

Рис. 8. Страница справки HelloWorldService

Если вы еще не включили метаданные службы на уровне компьютера, вы можете включить их в веб-приложении, добавив следующую конфигурацию поведения по умолчанию в файл web.config:

...

<system.serviceModel>

  <Поведения>

    <serviceBehaviors>

      <поведение><-- обратите внимание, что атрибут name отсутствует.>

        <serviceMetadata httpGetEnabled="true"/>

      </Поведение>

    </serviceBehaviors>

  </Поведения>

</system.serviceModel>

...

Вы также можете изменить другие параметры по умолчанию, выполнив процедуры, описанные в предыдущих разделах. Например, можно изменить сопоставление протокола по умолчанию, добавить конфигурации привязки по умолчанию или дополнительные конфигурации поведения по умолчанию. Если служба реализует более одного контракта службы, результирующий экземпляр ServiceHost будет настроен с одной конечной точкой HTTP для каждого контракта.

Например, предположим, что мы размещаем службу GreetingService (ранее) через SVC-файл, показанный ниже:

<-- GreetingService.svc -->

<%@ServiceHost Service="GreetingService"%>

Учитывая наше определение GreetingService, при первом переходе по адресу GreetingService.svc логика активации WCF создаст экземпляр ServiceHost и добавит две конечные точки HTTP по умолчанию для типа GreetingService (по одной для каждого контракта службы). Это можно проверить, перейдя к определению WSDL, и вы найдете два <элемента порта> в элементе <службы> .

В целом эти упрощения конфигурации WCF должны значительно упростить для разработчиков ASP.NET работу служб WCF в своих веб-приложениях, и это делает простейший вариант гораздо ближе к опыту, который разработчики использовали с веб-службами ASP.NET.

Активация без файлов

Хотя SVC-файлы упрощают предоставление служб WCF, еще более простым подходом будет определение конечных точек виртуальной активации в Web.config, тем самым устраняя потребность в SVC-файлах.

В WCF 4 можно определить конечные точки активации виртуальной службы, которые соответствуют типам служб в Web.config. Это позволяет активировать службы WCF без необходимости поддерживать физические SVC-файлы (т. е. "активация без файлов"). В следующем примере показано, как настроить конечную точку активации:

<Конфигурации>

  <system.serviceModel>

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="Greeting.svc" service="GreetingService"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

</Конфигурации>

Теперь можно активировать GreetingService, используя относительный путь Greeting.svc (относительно базового адреса веб-приложения). Чтобы проиллюстрировать это, я создал приложение IIS на своем компьютере с именем GreetingSite, которое я назначил пулу приложений "ASP.NET версии 4.0", и сопоставил его с каталогом проекта GreetingService, который содержит web.config, показанный выше. Теперь я могу просто перейти по папке https://localhost/GreetingSite/Greeting.svc без физического SVC-файла на диске. На рисунке 9 показано, как это выглядит в браузере.

Рис. 9. Пример активации без файлов

Обнаружение

Следующая важная функция WCF 4, которую мы обсудим, — это обнаружение служб. В некоторых специализированных средах, ориентированных на службы, существуют службы, расположение среды выполнения которых является динамическим и постоянно меняется. Например, рассмотрим среды, в которых различные типы устройств с поддержкой служб постоянно присоединяются к сети и покидают ее как часть общего бизнес-решения. Чтобы справиться с этой реальностью, клиенты должны динамически обнаруживать расположение конечных точек службы в среде выполнения.

WS-Discovery — это спецификация OASIS, которая определяет протокол на основе SOAP для динамического обнаружения расположения конечных точек службы во время выполнения. Протокол позволяет клиентам проверять конечные точки службы, которые соответствуют определенным критериям, чтобы получить список подходящих кандидатов. Затем клиент может выбрать определенную конечную точку из обнаруженного списка и использовать ее текущий адрес конечной точки среды выполнения.

WS-Discovery определяет два основных режима работы: нерегламентированный режим и управляемый режим. В нерегламентированном режиме клиенты проверяют службы, отправляя сообщения многоадресной рассылки. Платформа предоставляет механизм многоадресной рассылки UDP для этого нерегламентированного режима. Службы, соответствующие пробе, отвечают непосредственно клиенту. Чтобы свести к минимуму потребность в опросе клиентов, службы также могут "объявить" себя при присоединении к сети или выходе из нее, отправляя многоадресное сообщение клиентам, которые могут "прослушивать". Нерегламентированное обнаружение ограничивается протоколом, используемым для многоадресной рассылки сообщений. В случае с UDP получать сообщения смогут только службы, прослушивающие в локальной подсети.

При обнаружении управляемой службы вы предоставляете в сети прокси-сервер обнаружения, который "управляет" обнаруживаемыми конечными точками службы. Клиенты напрямую обращаются к прокси-серверу обнаружения, чтобы найти службы на основе критериев зондирования. Прокси-серверу обнаружения требуется репозиторий служб, которые он может сопоставить с запросом. Сведения о том, как прокси-сервер заполняется этой информацией, являются подробными сведениями о реализации. Прокси-серверы обнаружения можно легко подключить к активному репозиторию служб, их можно предварительно настроить со списком конечных точек, или прокси-сервер обнаружения может даже прослушивать объявления об обновлении кэша. В управляемом режиме объявления могут быть одноадресной рассылкой непосредственно получателю, возможно, через прокси-сервер обнаружения.

Платформа .NET 4.0 предоставляет базовые классы, необходимые для реализации собственного прокси-сервера обнаружения. Базовые классы абстрагируют сведения о протоколе обнаружения, поэтому вы можете просто сосредоточиться на логике, которую вы хотите, чтобы прокси-сервер обнаружения содержал. Например, необходимо только определить, что будет делать прокси-сервер обнаружения в ответ на сообщение пробы, сообщения объявления и разрешение сообщений.

WCF 4 предоставляет полную реализацию протокола WS-Discovery и поддержку нерегламентированного и управляемого режимов обнаружения. Мы кратко рассмотрим каждый из них ниже.

Простое обнаружение служб

Самый простой способ включить обнаружение служб — использовать нерегламентированный режим. WCF упрощает обнаружение служб в ведущих приложениях службы, предоставляя некоторые стандартные конечные точки обнаружения и поведение обнаружения служб. Чтобы настроить службу для обнаружения, просто добавьте стандартную конечную точку udpDiscoveryEndpoint, а затем включите <в ней поведение serviceDiscovery> .

Ниже приведен полный пример, демонстрирующий это.

<Конфигурации>

    <system.serviceModel>

      <services>

        <service name="CalculatorService">

          <endpoint binding="wsHttpBinding" contract="ICalculatorService" />

          <-- добавить стандартную конечную точку обнаружения UDP>

          <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </Услуги>

      <Поведения>

        <serviceBehaviors>

          <Поведение>

            <serviceDiscovery/><-- включить поведение обнаружения служб>

          </Поведение>

        </serviceBehaviors>

      </Поведения>

    </system.serviceModel>

</Конфигурации>

Это позволяет обнаруживать службу по протоколу UDP в локальной подсети. Затем клиенты могут воспользоваться преимуществами WS-Discovery во время выполнения, чтобы "обнаружить" фактический адрес работающей службы. WCF 4 упрощает для клиентов выполнение этой задачи с помощью стандартной конечной точки dynamicEndpoint.

Просто возьмите существующую конечную точку клиента, которую использовали для подключения к службе, удалите адрес и добавьте тег kind="dynamicEndpoint".

<Конфигурации>

    <system.serviceModel>

        <client>

          <Конечной точки

              name="calculatorEndpoint"

              kind="dynamicEndpoint"

              binding="wsHttpBinding"

              contract="ICalculatorService">

          </Конечной точки>

        </Клиента>

    </system.serviceModel>

</Конфигурации>

При первом вызове службы клиент отправляет многоадресный запрос на поиск служб, соответствующих контракту ICalculatorService, и попытается подключиться к нему. Различные параметры позволяют точно настроить serach, настроить привязки обнаружения и управлять процессом обнаружения. Вы также можете выполнить все это программным способом с помощью класса DiscoveryClient.

В следующем примере показано, как программно использовать UdpDiscoveryEndpoint для обнаружения конечной точки ICalculatorService, а затем вызвать ее:

Создание DiscoveryClient

DiscoveryClient discoveryClient =

    new DiscoveryClient(new UdpDiscoveryEndpoint());

Найдите конечные точки ICalculatorService в указанном область

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

FindResponse findResponse = discoveryClient.Find(findCriteria);

Просто выберите первую обнаруженную конечную точку

EndpointAddress address = findResponse.Endpoints[0]. Адрес;

Создание клиента целевой службы

CalculatorServiceClient client =

    new CalculatorServiceClient("calculatorEndpoint");

Подключение к обнаруженной конечной точке службы

Клиента. Endpoint.Address = address;

Console.WriteLine("Invoking CalculatorService at {0}", address);

Вызовите операцию Добавить службу.

double result = client. Add(100, 15.99);

Console.WriteLine("Add({0};{1}) = {2}", 100, 15.99, result);

После того как клиентская программа извлекла коллекцию обнаруженных конечных точек, она может использовать одну из них для фактического вызова целевой службы. На рисунке 10 показаны выходные данные выполнения кода клиента, показанного выше, предполагая, что служба также выполняется одновременно. Примечание. В этом примере операция Поиска в клиенте обнаружения является синхронной; Discovery также обеспечивает поддержку асинхронных операций поиска.

Рис. 10. Выходные данные выполнения кода клиента обнаружения

Использование областей при обнаружении конечных точек

В предыдущем примере клиент просто исследовал службы на основе типа контракта службы. Клиенты могут сузить результаты обнаружения, предоставляя дополнительные сведения о области при отправке проб обнаружения. Давайте рассмотрим простой пример, чтобы увидеть, как можно использовать "области" во время обнаружения.

Во-первых, службе необходимо связать одну или несколько областей с каждой конечной точкой, которую она собирается опубликовать для обнаружения. WCF 4 поставляется с поведением <endpointDiscovery> , которое можно использовать для определения набора областей, которые можно связать с определением конечной точки. В следующем примере показано, как связать две области с одной конечной точкой, определенной в службе:

<Конфигурации>

    <system.serviceModel>

      <services>

        <service name="CalculatorService"

                 behaviorConfiguration="calculatorServiceBehavior">

          <endpoint binding="wsHttpBinding"

                    contract="ICalculatorService"

                    behaviorConfiguration="ep1Behavior" />

          <endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </Услуги>

      <Поведения>

        <serviceBehaviors>

          <behavior name="calculatorServiceBehavior">

            <serviceDiscovery/>

          </Поведение>

        </serviceBehaviors>

        <endpointBehaviors>

          <behavior name="ep1Behavior">

            <endpointDiscovery>

               <-- областей, связанных с этим поведением конечной точки.>

              <Области>

                <add область="http://www.example.org/calculator"/>

                <add область="ldap:///ou=engineering,o=exampleorg,c=us"/>

              </Области>

            </endpointDiscovery>

          </Поведение>

        </endpointBehaviors>

      </Поведения>

    </system.serviceModel>

</Конфигурации>

Клиенты могут проверять конечные точки службы на основе определенных областей во время выполнения. Это можно сделать, добавив список целевых областей в экземпляр FindCriteria, который вы предоставляете для операции Find. В следующем коде показано, как обнаружить конечные точки ICalculatorService, соответствующие определенному область LDAP:

...

Создание DiscoveryClient

DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");

Найдите конечные точки ICalculatorService в указанном область

Uri область = new Uri("ldap:///ou=engineering,o=exampleorg,c=us");

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

findCriteria.Scopes.Add(область);

FindResponse findResponse = discoveryClient.Find(findCriteria);

...

Использование областей позволяет точно настроить реализацию обнаружения, чтобы клиенты могли легко обнаруживать конкретные конечные точки службы, представляющие для них интерес. Обнаружение также позволяет выполнять дальнейшую настройку. Например, службы могут добавлять пользовательские XML-метаданные в конечную точку. Эти сведения отправляются клиенту в ответ на запрос клиента.

Объявления служб

WCF 4 также упрощает настройку служб для "объявления" своих конечных точек при запуске. Это позволяет клиентам, которые "прослушивают", узнать о новых конечных точках службы прямо по мере присоединения к сети, тем самым уменьшая объем проверки (и многоадресного обмена сообщениями), выполняемого клиентами.

Вы можете настроить службу с конечной точкой объявления, используя <поведение serviceDiscovery> . Поведение <serviceDiscovery> позволяет определить коллекцию конечных точек объявления, которые будут предоставляться службой. В большинстве случаев можно использовать стандартный "udpAnnouncementEndpoint".

Вам также потребуется настроить службу со стандартным udpDiscoveryEndpoint, если вы хотите, чтобы она реагировала на пробы обнаружения, инициированные клиентами. В следующем примере показана типичная конфигурация:

<Конфигурации>

  <system.serviceModel>

    <services>

      <service name="CalculatorService">

        <endpoint binding="wsHttpBinding" contract="ICalculatorService"/>

        <endpoint kind="udpDiscoveryEndpoint"/>

      </service>

    </Услуги>

    <Поведения>

      <serviceBehaviors>

        <Поведение>

          <serviceDiscovery>

            <announcementEndpoints>

              <endpoint kind="udpAnnouncementEndpoint"/>

            </announcementEndpoints>

          </serviceDiscovery>

        </Поведение>

      </serviceBehaviors>

    </Поведения>

  </system.serviceModel>

</Конфигурации>

При использовании этой конфигурации служба будет объявлять о себе, когда она будет подключена, а также объявит о переходе в автономный режим. Чтобы воспользоваться этими объявлениями, необходимо специально спроектировать клиенты так, чтобы они прослушивали их во время выполнения. Для этого в клиентском приложении размещается служба объявлений, реализующая протокол объявления WS-Discovery.

WCF 4 поставляется с классом AnnouncementService, разработанным специально для этой цели. AnnouncementService предоставляет два обработчика событий: OnlineAnnouncementReceived и OfflineAnnouncementReceived. Клиентские приложения могут просто разместить экземпляр Службы объявлений с помощью ServiceHost и зарегистрировать обработчики событий для этих двух событий.

Всякий раз, когда служба выходит в режим "в сети" и объявляет о себе, размещенная в клиенте Служба объявлений будет получать объявление "в сети", а OnlineAnnouncementReceived срабатывает в клиенте. Когда служба перейдет в автономный режим, она отправляет объявление в автономном режиме, а OfflineAnnouncementReceived срабатывает в клиенте. Ниже показан пример клиентского приложения, в котором размещается Служба объявлений и реализуются обработчики для двух событий объявления:

class Client

{

    public static void Main()

    {

        Создание экземпляра Службы объявлений

        AnnouncementService announcementService = new AnnouncementService();

        Подписка на события объявления

        announcementService.OnlineAnnouncementReceived += OnOnlineEvent;

        announcementService.OfflineAnnouncementReceived += OnOfflineEvent;

        Создание ServiceHost для Службы объявлений

        using (Объявление ServiceHostServiceHost =

            new ServiceHost(announcementService))

        {

            Прослушивание объявлений, отправленных через многоадресную рассылку UDP

            announcementServiceHost.AddServiceEndpoint(

                new UdpAnnouncementEndpoint());

            announcementServiceHost.Open();

            Console.WriteLine("Прослушивание объявлений служб.");

            Console.WriteLine();

            Console.WriteLine("Нажмите клавишу <ВВОД> , чтобы завершить работу.");

            Console.ReadLine();

        }

    }

    static void OnOnlineEvent(object sender, AnnouncementEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Получено онлайн-объявление от {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    static void OnOfflineEvent(object sender, AnnouncementEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Получено автономное объявление от {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    ...

}

Рис. 11. Прослушивание сообщений об обнаружении

Теперь предположим, что я запускаю эту клиентную программу и оставлю ее на некоторое время. Затем я запустю несколько экземпляров ведущего приложения службы. При запуске каждой из них в окне консоли клиента появится сообщение с объявлением "online". Когда я закрою каждое из ведущих приложений службы, в окне консоли клиента появится сообщение об отключении от сети. На рисунке 11 показано результирующее окно консоли клиента после выполнения описанных выше действий.

Помните, что нерегламентированный режим обнаружения работает только в локальной подсети. Если вы хотите использовать WS-Discovery за пределами локальной сети, необходимо переключиться на режим управляемого обнаружения. WCF 4 также обеспечивает поддержку создания необходимых компонентов управляемого обнаружения.

Обнаружение управляемой службы

Реализация режима управляемого обнаружения немного сложнее, чем нерегламентированный режим, так как для этого требуется реализовать прокси-службу обнаружения. Прокси-служба обнаружения — это компонент, который будет отслеживать все доступные конечные точки службы. В этом примере мы используем функцию объявления для обновления прокси-сервера обнаружения. Существует множество других способов предоставления прокси-сервера обнаружения с соответствующими сведениями об обнаружении, например можно подключить существующую базу данных конечных точек и записать данные оттуда. Итак, как реализовать прокси-службу обнаружения?

WCF 4 поставляется с базовым классом DiscoveryProxy, который можно наследовать от для реализации прокси-службы обнаружения. На рисунке 12 показан запуск реализации пользовательской прокси-службы обнаружения. Примеры пакета SDK для .NET 4 содержат полный пример реализации для справки. Завершив реализацию прокси-службы обнаружения, ее необходимо разместить где-нибудь.

Рис. 12. Реализация пользовательской прокси-службы обнаружения

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

    ConcurrencyMode = ConcurrencyMode.Multiple)]

открытый класс MyDiscoveryProxy: DiscoveryProxyBase

{

    Репозиторий для хранения EndpointDiscoveryMetadata.

    Вместо этого также можно использовать базу данных или неструктурированный файл.

    Dictionary<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;

    public MyDiscoveryProxy()

    {

        this.onlineServices =

            new Dictionary<EndpointAddress, EndpointDiscoveryMetadata>();

    }

    OnBeginOnlineAnnouncement вызывается при получении сообщения Hello прокси-сервером.

    protected override IAsyncResult OnBeginOnlineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, обратный вызов AsyncCallback, состояние объекта)

    {

        Это. AddOnlineService(endpointDiscoveryMetadata);

        возвращает новый OnOnlineAnnouncementAsyncResult(callback, state);

    }

    protected override void OnEndOnlineAnnouncement(IAsyncResult result)

    {

        OnOnlineAnnouncementAsyncResult.End(result);

    }

    OnBeginOfflineAnnouncement вызывается при получении сообщения Bye прокси-сервером

    protected override IAsyncResult OnBeginOfflineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, обратный вызов AsyncCallback, состояние объекта)

    {

        Это. RemoveOnlineService(endpointDiscoveryMetadata);

        возвращает новый OnOfflineAnnouncementAsyncResult(callback, state);

    }

    protected override void OnEndOfflineAnnouncement(IAsyncResult result)

    {

        OnOfflineAnnouncementAsyncResult.End(result);

    }

    OnBeginFind вызывается, когда прокси-сервер получает сообщение запроса пробы.

    protected override IAsyncResult OnBeginFind(

        FindRequestContext findRequestContext, обратный вызов AsyncCallback, состояние объекта)

    {

        Это. MatchFromOnlineService(findRequestContext);

        возвращает новый OnFindAsyncResult(callback, state);

    }

    protected override void OnEndFind(IAsyncResult result)

    {

        OnFindAsyncResult.End(result);

    }

    ...

В этом примере я просто разместим службу MyDiscoveryProxy в консольном приложении.  Я настрою узел с двумя конечными точками: конечной точкой обнаружения и конечной точкой объявления. В следующем примере показано, как правильно разместить службу MyDiscoveryProxy с обеими этими конечными точками:

class Program

{

    public static void Main()

    {

        Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

        Объявление URIEndpointAddress =

            new Uri("net.tcp://localhost:9021/Announcement");

        ServiceHost proxyServiceHost = new ServiceHost(new MyDiscoveryProxy());

        DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

            new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));

        discoveryEndpoint.IsSystemEndpoint = false;

        AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

            new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

        proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

        proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

        proxyServiceHost.Open();

        Console.WriteLine("Служба прокси-сервера запущена.");

        Console.WriteLine();

        Console.WriteLine("Нажмите клавишу <ВВОД> , чтобы завершить работу службы.");

        Console.WriteLine();

        Console.ReadLine();

        proxyServiceHost.Close();

    }

}

После того как служба прокси-сервера обнаружения будет запущена, вы можете настроить свои службы так, чтобы они объявляли о себе непосредственно в прокси-службе обнаружения. Аналогичным образом можно настроить клиентские приложения для прямого проверки прокси-службы обнаружения (больше нет многоадресного обмена сообщениями).

Вы настраиваете службу так, чтобы она объявляла себя непосредственно службе прокси-сервера обнаружения, указывая адрес объявления прокси-сервера обнаружения при создании announcementEndpoint в ведущем приложении службы. В следующем примере показано, как это сделать:

...

URI baseAddress = new Uri("net.tcp://localhost:9002/CalculatorService/" +

    Guid.NewGuid(). ToString());

Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");

ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService), baseAddress);

ServiceEndpoint netTcpEndpoint = serviceHost.AddServiceEndpoint(

    typeof(ICalculatorService), new NetTcpBinding(), string. Пустой);

Создание конечной точки объявления, указывающей на размещенную прокси-службу

AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

    new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior();

serviceDiscoveryBehavior.AnnouncementEndpoints.Add(announcementEndpoint);

serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);

serviceHost.Open();

...

Затем можно настроить клиентские приложения для прямого взаимодействия со службой прокси-сервера обнаружения, указав адрес пробы прокси-сервера обнаружения при создании DiscoveryEndpoint в клиентском приложении. В следующем примере показан один из способов сделать это:

...

Создайте конечную точку обнаружения, которая указывает на прокси-службу.

Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

    new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));

Создание DiscoveryClient с помощью созданной ранее discoveryEndpoint

DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

Поиск конечных точек ICalculatorService

FindResponse findResponse = discoveryClient.Find(

    new FindCriteria(typeof(ICalculatorService)));

...

Теперь рассмотрим полный пример. Сначала запустим приложение прокси-сервера обнаружения, чтобы служба прокси-сервера обнаружения была доступна для использования. Затем я запустю экземпляр ведущего приложения службы, который объявит о себе с помощью прокси-сервера обнаружения. После этого в окне консоли приложения прокси обнаружения появится сообщение (см. рис. 13). Это показывает, что служба успешно объявила о себе в прокси-сервере обнаружения, а прокси-сервер обнаружения сохранил сведения о новой "сетевой" конечной точке службы. Теперь, если мы запустите приведенный выше код клиента, он проверит прокси-сервер обнаружения напрямую и получите адрес конечной точки целевой службы, работающей в данный момент.

Рис. 13. Выходные данные службы прокси-сервера обнаружения во время выполнения

Преимущество обнаружения управляемых служб заключается в том, что оно работает за пределами сети (оно основано на традиционных вызовах служб) и снижает потребность в многоадресном обмене сообщениями в решении обнаружения. Кроме того, так как клиенты проходят через прокси-сервер обнаружения для поиска служб, сами службы не должны постоянно работать, чтобы их можно было обнаружить.

Использование прокси-сервера расширенного обнаружения

Модель программирования WCF обеспечивает большую гибкость при реализации прокси-сервера обнаружения. Получение объявлений — это один из способов заполнения списка служб; однако это не единственный метод. Например, если среда уже содержит репозиторий служб, можно легко создать прокси-сервер обнаружения поверх этого хранилища, чтобы сделать репозиторий обнаруживаемым во время выполнения.

Прокси-сервер обнаружения можно настроить в нерегламентированном режиме или режиме управления. При работе в управляемом режиме клиенты взаимодействуют с прокси-сервером напрямую в одноадресной рассылке, используя объявления, пробы и разрешения. Прокси-сервер также передает ответ в одноадресной рассылке обратно отправителю.

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

Дополнительные сведения об этих расширенных сценариях обнаружения см. в руководстве по WS-Discovery по адресу http://www.oasis-open.org/committees/download.php/32184/WS-D-primer-wd-04.docx.

Служба маршрутизации

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

Например, в некоторых средах маршрутизация используется для реализации централизованной границы безопасности, через которую должны проходить все входящие сообщения. Некоторые используют методы маршрутизации на основе содержимого, чтобы определить, какую целевую службу использовать на основе содержимого конкретного входящего сообщения. Другие используют маршрутизацию для реализации моста протоколов, позволяя потребителям использовать один набор протоколов для обмена данными, а маршрутизатор использует другой набор протоколов для связи с целевой службой. Кроме того, нередко используется маршрутизация для различных методов балансировки нагрузки или даже управления версиями служб.

Независимо от причины, шаблон "промежуточной маршрутизации" является распространенным требованием при создании крупномасштабных решений SOA сегодня. В WCF 3.x не было официальной поддержки маршрутизации. Хотя платформа предоставляла необходимые API-интерфейсы для реализации собственных служб маршрутизации, для правильного выполнения этой работы было много работы. В журнале MSDN Magazine опубликовано несколько статей, в которых рассказывается, как это сделать.

Так как в наши дни маршрутизация является таким распространенным требованием, WCF 4 теперь поставляется с официальной "службой маршрутизации" в платформе, которую можно просто разместить и настроить в собственных решениях.

Общие сведения о службе маршрутизации

WCF 4 поставляется с новым классом RoutingService, который предоставляет универсальную реализацию маршрутизации WCF для использования в приложениях. Служба маршрутизации может обрабатывать сообщения маршрутизации по любому протоколу, поддерживаемому WCF, используя различные шаблоны обмена сообщениями, такие как односторонние сообщения, запросы и ответы и дуплексные сообщения). Ниже показано определение класса RoutingService:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,

    InstanceContextMode = InstanceContextMode.PerSession,

    UseSynchronizationContext = false, ValidateMustUnderstand = false),

 AspNetCompatibilityRequirements(RequirementsMode =

    AspNetCompatibilityRequirementsMode.Allowed)]

public sealed class RoutingService: // contracts allow different communication patterns

    ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter,

    IDuplexSessionRouter, IDisposable

{

    ... // реализация опущена

}

Как видите, класс RoutingService является производным от нескольких контрактов служб для поддержки нескольких шаблонов обмена сообщениями. Каждый контракт службы обеспечивает поддержку разных шаблонов обмена сообщениями, включая поддержку обмена данными на основе сеансов, когда это необходимо.

Вся цель RoutingService — получать входящие сообщения от потребителей и "направлять" их в соответствующую нижестоящей службе. RouterService определяет, какую целевую службу использовать, оценивая каждое входящее сообщение по набору фильтров сообщений. Таким образом, как разработчик, вы управляете поведением маршрутизации, определяя фильтры сообщений, как правило, в файле конфигурации. Целевые службы могут находиться на том же компьютере, что и RouterService, но это не обязательно— они также могут быть распределены по сети и для них могут потребоваться различные протоколы.

Размещение службы маршрутизации

RoutingService можно разместить в приложении так же, как и любую другую службу WCF. Просто создайте экземпляр ServiceHost и укажите RoutingService для типа службы. После вызова Open для экземпляра ServiceHost служба маршрутизации будет готова к "маршрутизации" сообщений, как показано ниже:

using System;

с помощью System.ServiceModel;

с помощью System.ServiceModel.Routing;

public static void Main()

{

    Создайте ServiceHost для типа RoutingService.

    using (ServiceHost serviceHost =

        new ServiceHost(typeof(RoutingService)))

    {

        попробуйте выполнить следующее

        {

            serviceHost.Open();

            Console.WriteLine("Служба маршрутизации запущена.");

            Console.WriteLine("Нажмите клавишу <ВВОД> , чтобы завершить работу маршрутизатора.");

            Теперь к службе можно получить доступ.

            Console.ReadLine();

            serviceHost.Close();

        }

        catch (CommunicationException)

        {

            serviceHost.Abort();

        }

    }

}

Вы также настраиваете RoutingService, как и любую другую службу, и именно в ней определяются фильтры маршрутизации. Сначала необходимо настроить его с помощью одной или нескольких конечных точек. При определении конечной точки маршрутизации вы выбираете привязку WCF и один из контрактов службы маршрутизации, реализованных службой маршрутизации, показанной выше (например, ISimplexDatagramRouter, IRequestReplyRouter и т. д.). Если требуется поддержка нескольких шаблонов обмена сообщениями или привязок WCF, в службе маршрутизации можно предоставить несколько конечных точек.

В следующем примере показано, как настроить RoutingService с четырьмя конечными точками маршрутизации: две, использующие BasicHttpBinding (односторонняя и "запрос-ответ") и две , использующие WSHttpBinding (односторонняя и "запрос-ответ"). Обратите внимание, что это аналогично настройке любой другой службы WCF:

<Конфигурации>

  <system.serviceModel>

    <services>

      <служба --ROUTING -->

      <service behaviorConfiguration="routingData"

          name="System.ServiceModel.Routing.RoutingService">

        <узел>

          <baseAddresses>

            <add baseAddress="https://localhost:8000/routingservice/router"/>

          </baseAddresses>

        </Узла>

        <!--

          Определите и настройте конечную точку, которую маршрутизатор будет прослушивать, и

          Контракт, который мы хотим использовать. Предоставленные контракты маршрутизатора:

          ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter и

          IDuplexSessionRouter.

         -->

        <endpoint address="oneway-basic"

                  binding="basicHttpBinding"

                  name="onewayEndpointBasic"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <endpoint address="oneway-ws"

                  binding="wsHttpBinding"

                  name="onewayEndpointWS"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <endpoint address="twoway-basic"

                  binding="basicHttpBinding"

                  name="reqReplyEndpointBasic"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

        <endpoint address="twoway-ws"

                  binding="wsHttpBinding"

                  name="reqReplyEndpointWS"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

      </service>

    </Услуги>

    ...

Интерфейсы ISimplexDatagramRouter и IRequestReplyRouter определяют универсальные определения односторонних контрактов службы и контрактов службы "запрос-ответ", которые можно использовать в сочетании с контрактами служб, зависящими от бизнеса. Ниже показано, как эти интерфейсы были определены в WCF:

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

открытый интерфейс ISimplexDatagramRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]

    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback,

        состояние объекта);

    void EndProcessMessage(IAsyncResult result);

}

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

открытый интерфейс IRequestReplyRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay= false, Action = "*",

        ReplyAction = "*")]

    [GenericTransactionFlow(TransactionFlowOption.Allowed)]

    IAsyncResult BeginProcessRequest(Message message, AsyncCallback callback,

        состояние объекта);

    Message EndProcessRequest(IAsyncResult result);

}

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

Настройка службы маршрутизации с фильтрами сообщений

Вы можете настроить routingService с фильтрами сообщений с помощью кода или конфигурации (как и все остальное в WCF). WCF 4 предоставляет RoutingBehavior для управления фильтрами сообщений маршрутизации. Сначала необходимо включить RoutingBehavior в RouterService, а затем указать имя таблицы фильтров, которую вы хотите использовать с этим конкретным экземпляром RoutingService:

<Конфигурации>

  <system.serviceModel>

    ...

    <Поведения>

      <serviceBehaviors>

        <behavior name="routingData">

          <serviceMetadata httpGetEnabled="True"/>

          <-- определите поведение маршрутизации и укажите имя таблицы фильтров.>

          <routing filterTableName="filterTable1" />

        </Поведение>

      </serviceBehaviors>

    </Поведения>

    ...

Если вы посмотрите в предыдущем примере, где мы настроили RoutingService с конечными точками, вы увидите, что мы применили к службе поведение routingData с помощью атрибута behaviorConfiguration. Далее необходимо определить таблицу фильтров с именем filterTable1.

Однако прежде чем мы сможем определить таблицу фильтров, нам потребуются определения конечных точек для целевых служб, к которые мы намерены направлять маршрут. Эти целевые конечные точки определяются в разделе конфигурации клиента> WCF<, так как routingService по сути является "клиентом" при пересылке сообщений в целевую службу. В следующем примере показано, как определить две целевые конечные точки, к которым можно направлять маршрут:

<Конфигурации>

    ...

    <-- Определите конечные точки клиента, с которыми будет взаимодействовать маршрутизатор.

         Это назначения, в которые маршрутизатор будет отправлять сообщения. -->

    <client>

      <endpoint name="CalculatorService1"

       address="https://localhost:8000/servicemodelsamples/calcservice1"

       binding="wsHttpBinding" contract="*" />

      <endpoint name="CalculatorService2"

       address="https://localhost:8001/servicemodelsamples/calcservice2"

       binding="wsHttpBinding" contract="*" />

    </Клиента>

    ...

Теперь мы можем определить фактическую таблицу фильтров, которая будет определять логику маршрутизации во время выполнения. Вы определяете записи таблицы фильтров в элементе <filterTables> . Каждая запись в <filterTable> определяет сопоставление между фильтром маршрутизации и целевой конечной точкой. Вы определяете "фильтры", которые вы хотите использовать в <элементе filters> . Каждая <запись фильтра> указывает, какой тип фильтра вы хотите использовать вместе с данными фильтра (например, значение действия, выражение XPath и т. д.).

В следующем примере показано, как настроить таблицу фильтров с одним фильтром, который сопоставляется с конечной точкой CalculatorService1. В этом случае фильтр MatchAll соответствует всем входящим сообщениям:

<Конфигурации>

    ...

    <раздел --ROUTING -->

    <Маршрутизации>

      <-- Определите фильтры, которые будет использовать маршрутизатор. -->

      <filters>

        <filter name="MatchAllFilter1" filterType="MatchAll" />

      </Фильтры>

      <-- Определите таблицу фильтров, содержащую фильтр matchAll>

      <filterTables>

        <filterTable name="filterTable1">

            <-- сопоставьте фильтр с ранее определенной конечной точкой клиента.

                 Сообщения, соответствующие этому фильтру, будут отправлены по данному назначению. -->

          <add filterName="MatchAllFilter1" endpointName="CalculatorService1" />

        </filterTable>

      </filterTables>

    </Маршрутизации>

  </system.serviceModel>

</Конфигурации>

Мы можем убедиться, что маршрутизация работает правильно, запустив ведущее приложение службы маршрутизации, ведущее приложение CalculatorService1 и клиент, предназначенный для отправки сообщений в одну из конечных точек маршрутизатора. При запуске клиента сообщения поступают в CalculatorService 1 после их "маршрутизации" промежуточной службой маршрутизации (см. рис. 14, рис. 15 и рис. 16).

Рис. 14. Ведущее приложение RoutingService

Рис. 15. Клиент, предназначенный для RoutingService в https://localhost:8000/routingservice/router

Рис. 16. Целевая служба (CalculatorService1)

Фильтры сообщений и маршрутизация на основе содержимого

WCF поставляется с несколькими встроенными классами MessageFilter, которые можно использовать в сочетании с фильтрами сообщений маршрутизации для проверки содержимого входящих сообщений.

Например, WCF предоставляет ActionMessageFilter, который позволяет сопоставлять определенные WS-Addressing "action" значения. WCF также предоставляет EndpointAddressMessageFilter, EndpointNameMessageFilter и PrefixEndpointAddressMessageFilter, которые позволяют сопоставлять конкретные сведения о конечной точке. Одним из наиболее гибких является XPathMessageFilter, который позволяет вычислять выражения XPath для входящих сообщений. Все эти фильтры позволяют выполнять маршрутизацию на основе содержимого в решении.

В дополнение к этим встроенным типам MessageFilter WCF 4 также позволяет определить настраиваемые фильтры сообщений, которые являются одной из основных точек расширяемости для RoutingService.

Рассмотрим пример выполнения маршрутизации на основе содержимого на основе значений действий. Предположим, мы хотим направить половину операций CalculatorService в CalculatorService1, а другую половину — в CalculatorService2. Это можно сделать, определив фильтры для каждого из различных значений действия CalculatorService и сопоставив половину из них с каждой конечной точкой целевой службы, как показано ниже:

<Конфигурации>

    ...

    <раздел --ROUTING -->

    <Маршрутизации>

      <-- Определите фильтры, которые будет использовать маршрутизатор. -->

     <filters>

        <filter name="addFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Add"/>

        <filter name="subFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Subtract"/>

        <filter name="mulFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Multiply"/>

        <filter name="divFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Divide"/>

      </Фильтры>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable>

      </filterTables>

    </Маршрутизации>

  </system.serviceModel>

</Конфигурации>

Теперь при запуске решения и выполнении клиента, который вызывает все четыре операции, мы увидим, что половина операций отображается в каждом окне консоли службы (см. рис. 17 и рис. 18).

Рис. 17. Выходные данные CalculatorService1

Рис. 18. Выходные данные CalculatorService2

XPathMessageFilter обеспечивает еще большую гибкость, так как вы можете предоставить различные выражения XPath для оценки входящих сообщений. Выражения XPath могут оценивать любую часть входящего сообщения, включая заголовки SOAP или текст SOAP. Это обеспечивает большую гибкость при создании фильтров сообщений на основе содержимого. Чтобы понять механизм XPathMessageFilter, ниже показано, как переписать последний пример с помощью выражений XPath.

<настройка>

    ...

    <раздел --ROUTING -->

    <Маршрутизации>

      <-- Определите фильтры, которые будет использовать маршрутизатор. -->

     <filters>

        <filter name="addFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Add'"/>

        <filter name="subFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Subtract'"/>

        <filter name="mulFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Multiply'"/>

        <filter name="divFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Divide'"/>

      </Фильтры>

      <namespaceTable>

        <add prefix="s" namespace="http://www.w3.org/2003/05/soap-envelope" />

        <add prefix="wsa" namespace="http://www.w3.org/2005/08/addressing" />

      </namespaceTable>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable>

      </filterTables>

    </Маршрутизации>

  </system.serviceModel>

</Конфигурации>

Обратите внимание, что атрибут filterData содержит выражение XPath, которое будет вычисляться по входящему сообщению (выражения просто проверка значения действия в этом примере). Обратите внимание, что я также определил набор привязок префиксов пространства имен с помощью <элемента namespaceTable> . Это необходимо, если вы хотите использовать префиксы пространства имен в выражениях XPath, как это было сделано выше. Повторное выполнение решения с такой конфигурацией дает те же результаты, что и раньше (см. рис. 17 и рис. 18).

Этот метод фильтрации XPath потребуется использовать каждый раз, когда потребуется маршрутизировать сообщения на основе пользовательских заголовков SOAP или содержимого, найденного в тексте сообщения SOAP.

Связывание протоколов

В предыдущих примерах мы использовали ту же привязку WCF (WSHttpBinding) для взаимодействия между клиентом и маршрутизатором, а также между маршрутизатором и целевыми службами. Служба маршрутизации может обеспечить связь между большинством привязок WCF. Например, может потребоваться настроить маршрутизатор таким образом, чтобы клиенты взаимодействовали с ним через WSHttpBinding, но затем маршрутизатор взаимодействует с подчиненными целевыми службами с помощью NetTcpBinding или NetNamedPipeBinding.

Давайте посмотрим, как настроить RoutingService для обработки этого сценария. Мы оставим конфигурацию конечной точки RoutingService той же, что и выше, что позволяет потребителям взаимодействовать с RoutingService через BasicHttpBinding или WSHttpBinding. Но теперь мы изменим определения конечных точек клиента для целевых служб, чтобы использовать NetTcpBinding и NetNamedPipeBinding, как показано ниже:

<Конфигурации>

    ...

    <-- Определите конечные точки клиента, с которыми будет взаимодействовать маршрутизатор.

         Это назначения, в которые маршрутизатор будет отправлять сообщения. -->

    <client>

      <endpoint name="CalculatorService1"

       address="net.tcp://localhost:8001/servicemodelsamples/calcservice1"

       binding="netTcpBinding" contract="*" />

      <endpoint name="CalculatorService2"

       address="net.pipe://localhost/servicemodelsamples/calcservice2"

       binding="netNamedPipeBinding" contract="*" />

    </Клиента>

    ...

И, конечно, нам потребуется обновить приложения CalculatorService1 и CalculatorService2 для поддержки совместимых конечных точек NetTcpBinding и NetNamedPipeBinding соответственно. При такой конфигурации потребители могут взаимодействовать с routingService с помощью BasicHttpBinding/WSHttpBinding, а маршрутизатор будет взаимодействовать с целевыми службами с помощью NetTcpBinding или NetNamedPipeBinding в зависимости от того, в какую службу направляется сообщение.

Передача ошибок и отказоустойчивость

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

В следующем примере показано, как определить список конечных точек резервного копирования в элементе <backupLists> , который можно связать с записями таблицы фильтров:

<Конфигурации>

    ...

    <раздел --ROUTING -->

    <Маршрутизации>

      ... <! -- Определите фильтры, которые будет использовать маршрутизатор. -->

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="subFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="divFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

        </filterTable>

      </filterTables>

      <backupLists>

        <backupList name="backupEndpoints">

          <add endpointName="CalculatorService2"/>

        </backupList>

      </backupLists>

    </Маршрутизации>

  </system.serviceModel>

</Конфигурации>

Обратите внимание, что в этом примере мы настроили все записи таблицы фильтров для пересылки в CalculatorService1, так как CalculatorService2 теперь является нашей резервной конечной точкой, которая будет использоваться только в том случае, если CalculatorService1 приводит к timeoutException, CommunicationException или производного типа исключения. Например, если снова запустить решение и закрыть CalculatorService1, а затем выполнить клиентскую программу, все сообщения будут отображаться в CalculatorService2. Важно еще раз отметить, что вся эта конфигурация маршрутизации может выполняться динамически в коде ведущего приложения.

Поведение многоадресной маршрутизации

RoutingService также поддерживает автоматическую маршрутизацию определенного входящего сообщения в несколько назначений в режиме многоадресной рассылки. Если входящее сообщение соответствует нескольким фильтрам, найденным в настроенной таблице фильтров, Служба маршрутизации автоматически перенаправит сообщение в каждую из целевых конечных точек, связанных с "сопоставленными" фильтрами.

В следующем примере показаны две записи маршрутизации, настроенные с одинаковым фильтром с подстановочными знаками, который соответствует всем входящим сообщениям:

<Конфигурации>

    ...

    <раздел --ROUTING -->

    <Маршрутизации>

      <-- Определите фильтры, которые будет использовать маршрутизатор. -->

     <filters>

        <filter name="wildcardFilter" filterType="MatchAll" />

      </Фильтры>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="wildcardFilter" endpointName="CalculatorService1"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService2"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService3"/>

        </filterTable>

      </filterTables>

    </Маршрутизации>

  </system.serviceModel>

</Конфигурации>

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

Это поведение многоадресной рассылки состоит из возможностей моста протокола и обработки ошибок, описанных в предыдущих разделах. Единственная проблема заключается в том, что многоадресная рассылка работает только для односторонней или дуплексной связи, но не для обмена запросами и ответами, так как базовая система должна поддерживать соотношение "один к одному" между исходящими запросами и входящими ответами.

Улучшенная поддержка REST

WCF 4 поставляется с несколькими новыми функциями, которые пригодится при создании служб RESTful с помощью WCF.  Этот набор функций теперь называется веб-службами WCFHttp. Они включают поддержку автоматической страницы справки, описывающей службу RESTful для потребителей, упрощенное кэширование HTTP, выбор формата сообщений, исключения, поддерживающие REST, интеграцию ASP.NET маршрутизации, некоторые новые шаблоны проектов Visual Studio и многое другое. У нас не будет места, чтобы охватить все эти функции здесь подробно, но я дам вам краткое введение в некоторые из моих избранных ниже, а также ссылки на более подробную информацию об остальных.

Многие из этих функций были впервые представлены начальным комплектом WCF REST в прошлом году и теперь становятся официальной платформой. В будущем вы можете увидеть дополнительные функции начального набора WCF REST.

Страница автоматической справки

При использовании класса WebServiceHost в WCF 4 службы RESTful будут автоматически пользоваться преимуществами автоматической страницы справки. Это очень необходимое дополнение при использовании REST, учитывая отсутствие метаданных WSDL и создание кода на стороне клиента. Это значительно упрощает пользователям определение того, как начать работу со службой, поэтому обычно рекомендуется включить эту новую функцию.

При использовании класса WebServiceHost для размещения службы он автоматически настраивает службу с помощью WebHttpBehavior и добавляет конечную точку HTTP по умолчанию, настроенную с webHttpBinding (по базовому HTTP-адресу). В WCF 4 класс WebHttpBehavior поставляется со свойством HelpEnabled, которое определяет, включена ли новая страница справки в узле. В следующем примере конфигурации показано, как включить функцию автоматической страницы справки для определенной конечной точки REST.

<Конфигурации>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    <Поведения>

      <endpointBehaviors>

        <behavior name="HelpBehavior">

          <webHttp helpEnabled="true" />

        </Поведение>

      </endpointBehaviors>

    </Поведения>

    <services>

      <service name="CounterResource">

        <endpoint behaviorConfiguration="HelpBehavior"

                  binding="webHttpBinding"

                  contract="CounterResource" />

      </service>

    </Услуги>

  </system.serviceModel>

</Конфигурации>

Чтобы просмотреть страницу справки, перейдите по базовому адресу службы с добавлением справки в конец URL-адреса (см. рис. 19).

Рис. 19. Страница автоматической справки для служб RESTFul

Страница справки содержит понятное описание каждой операции с заметками [WebGet] или [WebInvoke], а для каждой из них — шаблон URI, поддерживаемую http-операцию и поддерживаемые форматы сообщений, в основном все, что нужно знать потребителю (см. рис. 20). Вы также можете предоставить более понятное описание, применив атрибут [Description] к каждой операции.

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

Рис. 20. Страница автоматической справки для определенной операции

Эта новая функция страницы справки автоматически делает службы RESTful более удобными для обнаружения, что в конечном итоге упрощает их использование другими пользователями. Пользователи могут обнаружить структуру URI службы, поддерживаемые http-операции и форматы запросов и ответов, а описание всегда будет синхронизировано с кодом WCF, как и с веб-службами ASP.NET.

Поддержка кэширования HTTP

Одним из основных потенциальных преимуществ REST является кэширование HTTP. Тем не менее, чтобы понять это преимущество, необходимо использовать различные заголовки кэширования HTTP в запросах и ответах. Это можно сделать в рамках операций службы WCF, вручную перейдя к заголовкам запроса и ответа через экземпляр WebOperationContext, но это нетривиальная задача.

Таким образом, WCF 4 поставляется с более простой моделью для управления кэшированием с помощью атрибута [AspNetCacheProfile], которую можно декларативно применять к операциям GET. Этот атрибут позволяет указать имя ASP.NET профиля кэширования для каждой операции, а в фоновом режиме есть инспектор кэширования (CachingParameterInspector), который отвечает за обработку всех базовых сведений о кэшировании HTTP.

Реализация [AspNetCacheProfile] основана на стандартном механизме кэширования выходных данных ASP.NET. В следующем примере показано, как применить атрибут [AspNetCacheProfile] к операции [WebGet]:

...

[AspNetCacheProfile("CacheFor60Seconds")]

[WebGet(UriTemplate=XmlItemTemplate)]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

...

После этого необходимо определить профиль кэширования ASP.NET выходных данных с именем CacheFor60Seconds в файле web.config. В следующем web.config показано, как это сделать.

<Конфигурации>

  <system.web>

    <Кэширование>

      <outputCacheSettings>

        <outputCacheProfiles>

          <add name="CacheFor60Seconds" duration="60" varyByParam="format" />

        </outputCacheProfiles>

      </outputCacheSettings>

    </Кэширование>

  </System.web>

  <system.serviceModel>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  </system.serviceModel>

</Конфигурации>

Обратите внимание, что для профиля кэширования ASP.NET настроено кэширование выходных данных в течение 60 секунд и настроено изменение кэша в зависимости от переменной строки запроса format. Это важно, так как данная служба поддерживает как XML, так и JSON, которыми вы управляете с помощью переменной формата (например, "?format=json"). Служба должна кэшировать ответы XML и JSON независимо друг от друга.

В этом файле конфигурации также показано, как включить режим совместимости ASP.NET, который требуется, если вы хотите воспользоваться различными функциями ASP.NET, такими как кэширование выходных данных.

Атрибут [AspNetCacheProfile] значительно упрощает использование кэширования HTTP без необходимости работать с заголовками кэширования HTTP напрямую. Базовое поведение WCF отвечает за внедрение в ответ заголовков HTTP Cache-Control, Date, Expires и Vary, которые клиенты также могут использовать, чтобы определить правильную семантику кэширования для будущих кругового пути.

Выбор формата сообщения

Если вы вернетесь на рис. 19, вы заметите, что служба CounterResource поддерживает форматы XML и JSON для операций GET, POST и PUT. Это стало возможным с версии WCF 3.5 с помощью свойств RequestFormat и ResponseFormat, найденных в атрибутах [WebGet] и [WebInvoke].

Это удалось сделать в службе CounterResource, определив отдельный контракт операции для каждой версии — один для XML-версии, а другой — для версии JSON, как показано ниже:

...

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

[WebGet(UriTemplate = "?format=json", ResponseFormat=WebMessageFormat.Json)]

[OperationContract]

public Counter GetItemInJson()

{

    return HandleGet();

}

...

Это, к сожалению, означает, что для каждой логической операции требуется два контракта операции, если вы хотите поддерживать форматы XML и JSON. В случае со службой CounterResource мне требовалось иметь шесть контрактов операций для поддержки XML и JSON для операций GET, POST и PUT.

WCF 4 значительно упрощает обработку этого сценария, предоставляя поддержку автоматического выбора формата на основе заголовков HTTP Accept, что является лучшим способом. Позвольте мне объяснить, как это работает.

Во-первых, для каждой логической операции требуется только один контракт операции:

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    return HandleGet();

}

Затем мы автоматически выделим формат на стандартном веб-сайтеHttpEndpoint, как показано ниже:

<Конфигурации>

  <system.serviceModel>

    <standardEndpoints>

      <webHttpEndpoint>

        <-- для автоматического создания веб-конечной точки используется стандартная конечная точка . -->

        <standardEndpoint name="" helpEnabled="true"

            automaticFormatSelectionEnabled="true"/>

      </webHttpEndpoint>

    </standardEndpoints>

  </system.serviceModel>

</Конфигурации>

Благодаря этому служба теперь может обрабатывать и возвращать сообщения XML или JSON. Он определяет, какой формат следует использовать, сначала проверив заголовок HTTP Accept, найденный в сообщении запроса. Если это не сработает, он будет использовать тот же формат сообщения, что и сообщение запроса, предполагая, что это XML или JSON, в противном случае он будет использовать формат по умолчанию для конкретной операции.

Теперь клиент должен определить, какой формат использовать с помощью заголовков Http Content-Type и Accept. Заголовок Content-Type указывает формат в сообщении запроса, а заголовок Accept указывает, какой формат клиент "принимает" из службы. Например, если клиент хочет получить JSON обратно от службы, он должен указать следующий заголовок HTTP Accept в запросе:

Accept: application/json

Это легко сделать в любой модели программирования HTTP-клиента, а также с помощью таких средств, как Fiddler. На рисунке 21 показано, как использовать Fiddler для получения JSON обратно из нашей новой и улучшенной службы.

Рис. 21. Использование заголовка HTTP Accept для получения JSON

WCF 4 также предоставляет новые API, которые упрощают явное указание формата сообщения во время выполнения. В следующем коде показано, как расширить операцию GetItem, написав код, который сначала ищет параметр строки запроса format и явно задает соответствующий формат ответа. Если он не находит параметр format, он будет просто полагаться на заголовок Accept, как раньше.

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    Значение , если указан параметр строки запроса формата,

    задайте для этого формата ответа. Если нет такого

    Параметр строки запроса существует, будет использоваться заголовок Accept

    string formatQueryStringValue =

       WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters[

       "format"];

    if (!string). IsNullOrEmpty(formatQueryStringValue))

    {

        if (formatQueryStringValue.Equals("xml",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

        }

        else if (formatQueryStringValue.Equals("json",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

        }

        else

        {

            вызовите новую строку> WebFaultException<(string. Format("Неподдерживаемый формат "{0}"",

               formatQueryStringValue), HttpStatusCode.BadRequest);

        }

    }

    return HandleGet();

}

В конце концов, эти новые функции делают это так, что вам больше не придется жестко кодировать тип формата сообщения в контрактах операций [WebGet] и [WebInvoke], как в WCF 3.5.

Обработка ошибок RESTful

Так как службы RESTful не используют SOAP, в вашем распоряжении больше нет стандартного механизма сбоя SOAP, что позволяет автоматически сопоставлять исключения .NET и сообщения об ошибках SOAP. При создании служб REST в WCF 3.5 приходилось вручную создавать ответное сообщение HTTP всякий раз, когда вы хотите настроить сообщение об ошибке HTTP, отправляемого клиенту.

В WCF 4 вы найдете новый класс с именем WebFaultException<T> , который значительно упрощает передачу "веб-ошибок" (например, ошибок HTTP) обратно потребителям. Он очень похож на FaultException<T> в WCF, но вы можете указать код состояния HTTP и тип сведений, чтобы предоставить дополнительные сведения.

В следующем примере показано, как вернуть ошибку HTTP 400 (недопустимый запрос), когда пользователь указывает неподдерживаемый тип формата. Я просто использую строку для типа сведений:

if (!string). IsNullOrEmpty(format))

{

    if (format. Equals("xml", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

    }

    else if (format. Equals("json", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

    }

    else

    {

        вызовите новую строку> WebFaultException<(string. Format("Неподдерживаемый формат "{0}"",

           format), HttpStatusCode.BadRequest);

    }

}

Эта новая функция позволяет гораздо более естественно возвращать стандартные сообщения об ошибках HTTP, просто создавая исключения, как обычно в службах на основе SOAP.

Интеграция WCF с маршрутами ASP.NET

Возможности маршрутизации на основе URL-адресов, доступные как в WCF 4, так и в ASP.NET 4, много общего. Они оба позволяют делать одно и то же — по сути сопоставлять шаблоны URL-адресов с методами в классах. Однако между двумя моделями существует одно существенное различие.

Подход WCF 4 связывает структуру шаблона URL-адреса с одним классом с помощью атрибутов [WebGet] и [WebInvoke], применяемых к определению класса во время разработки. По мере роста и развития службы с течением времени это может привести к созданию большого монолитного дизайна, который не может быть разбит на более мелкие блоки. Подход ASP.NET 4, с другой стороны, отделяет логику маршрутизации от определения целевого класса, тем самым позволяя при необходимости сопоставлять маршруты служб между многочисленными определениями классов.

WCF 4 теперь позволяет интегрировать подсистему маршрутизации ASP.NET со службами WCF 4, что позволяет использовать ASP.NET модель маршрутизации поверх служб WCF.

Это можно сделать в методе RegisterRoutes Global.asax, используя преимущества нового класса ServiceRoute, который позволяет сопоставить маршрут ASP.NET с классом службы WCF:

private void RegisterRoutes()

{

   Фабрика WebServiceHostFactory = new WebServiceHostFactory();

   RouteTable.Routes.Add(new ServiceRoute("Bookmarks", factory,

      typeof(BookmarkService)));

   RouteTable.Routes.Add(new ServiceRoute("Users", factory,

      typeof(UserService));

}

Я вызываю RouteTable.Routes.Add дважды, чтобы добавить новые маршруты для двух разных классов служб WCF. Первый маршрут сопоставляет "/Bookmarks" с классом BookmarkService, а второй маршрут сопоставляет "/Users" с классом UserService. Обратите внимание, что оба маршрута настроены для использования WebServiceHostFactory.

Теперь, когда мы используем атрибуты [WebGet] и [WebInvoke] в определениях классов служб WCF, мы будем использовать относительные пути, и они будут относительны к ASP.NET маршруту, указанному здесь.

Шаблоны проектов REST

Одной из аккуратных функций в Visual Studio 2010 является диспетчер расширений, доступ к которому можно получить из средств | Диспетчер расширений. Диспетчер расширений позволяет корпорации Майкрософт и другим сторонним организациям интегрировать новые шаблоны проектов, элементы управления и средства в интерфейс Visual Studio 2010 с помощью простого нажатия кнопки. Для групп разработчиков продуктов Майкрософт это здорово, так как это позволяет отправлять вещи после RTM и по-прежнему делать их официальными расширениями, предоставляемыми корпорацией Майкрософт.

Если открыть диспетчер расширений и развернуть узел "Шаблоны", вы найдете дочерний узел с именем "WCF". Щелкните "WCF", и вы увидите четыре новых шаблона службы REST WCF: по одному для каждой версии .NET (3.5 против 4.0) и по одному для каждого языка (C# и VB.NET), как показано на рисунке 22.

Рис. 22. Новые шаблоны проектов REST WCF в диспетчере расширений

Вы можете выбрать эти новые шаблоны проектов, скачать их в локальную установку Visual Studio 2010 и использовать их как любой другой тип проекта. Новый тип проекта REST можно найти в разделе Visual C# | Интернет | Приложение-служба REST WCF (предполагается, что вы установили версию C#).

При его использовании для создания нового проекта вы заметите, что создаваемое приложение службы REST WCF использует большинство новых функций WCF 4, которые я выделил в этом разделе.

Дополнительные сведения

В дополнение к тому, что мы обсуждали здесь, WCF 4 поставляется с несколькими более расширенными возможностями REST и новыми расширениями API WCF, которые упрощают обработку пользовательских форматов сообщений (не XML или JSON), возврат шаблонов "представлений" с помощью новой функции T4, реализацию условной поддержки GET и ETag, реализацию оптимистичного параллелизма и создание исходящих ссылок.

Дополнительные сведения обо всех новых функциях WCF 4, в том числе о тех, которые нам не хватало, см. в блоге о конечной точке .NET и найдите запись в разделе Знакомство со службами WCF WebHttp в .NET 4. Команда предоставила серию блогов из 12 частей, в которых рассматривается каждая новая функция по одной записи блога за раз, а также множество примеров кода и пошаговые инструкции.

Службы рабочего процесса

Одной из функциональных областей, которые получили наибольшее внимание в .NET 4, были "службы рабочих процессов". Корпорация Майкрософт вкладывает значительные средства в улучшение интеграции между WCF и WF, чтобы обеспечить обширную декларативную модель программирования для создания широкого спектра приложений.

Основные сведения о службах рабочих процессов

WF предоставляет декларативную модель программирования, которая повышает уровень абстракции для тех, кто пишет логику. В конечном итоге WF предоставляет платформу для написания собственных языков, определяя собственную библиотеку бизнес-предметных действий. Затем он предоставляет визуальный конструктор для создания этих действий в программы и среду выполнения, которая знает, как управлять выполнением этих программ.

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

Рис. 23. Службы рабочих процессов

WF отличается от других платформ разработки тем, что предоставляет эти функции, но по-прежнему позволяет программировать с помощью последовательной логики программирования управления потоком, которая, как правило, гораздо проще для разработчиков читать и писать код для понимания.

Если вы создаете службы WCF, которые являются длительными по своей природе или могут воспользоваться некоторыми другими преимуществами, которые я только что описал, вы можете реализовать службы WCF с помощью рабочего процесса WF. Кроме того, вы можете использовать WF для координации логики использования других внешних служб.

На рисунке 23 показаны эти понятия.

Хотя это было возможно с .NET 3.5, .NET 4 добилась значительных успехов в улучшении среды разработки и предоставлении некоторых необходимых функций, отсутствующих в .NET 3.5.

Объединяя миры WCF и WF, вы получаете лучшее из обоих миров. Благодаря конструкторам WF вы получаете декларативную модель программирования, удобный интерфейс для разработчиков, мощную среду выполнения для управления длительными службами и широкие возможности взаимодействия, предоставляемые WCF.

Создание первой службы рабочих процессов

Чтобы почувствовать новые возможности разработчика служб рабочих процессов, я рассмотрим полный пример его создания с помощью .NET 4 и нового конструктора Visual Studio 2010.

Если открыть Visual Studio 2010 и выбрать Файл | Новый проект. Новый проект рабочего процесса будет находиться в шаблонах WCF— он называется "Приложение службы рабочих процессов WCF". Я выберу этот шаблон проекта, присвою ему имя HelloWorldWorkflowService и создам новый проект.

Рис. 24. Шаблоны проектов служб рабочих процессов Visual Studio 2010

После создания новый проект будет содержать просто два файла: файл Service1.xamlx, содержащий декларативное определение службы рабочего процесса, и файл Web.config, содержащий конфигурацию службы.

Одна из наиболее привлекательных вещей о новой модели служб рабочих процессов в .NET 4 заключается в том, что все определение службы можно определить в XAML.   В нашем новом проекте файл Service1.xamlx содержит определение службы, а реализация представляет собой просто рабочий процесс на основе XAML. Файл Web.config содержит конфигурацию службы WCF. Здесь вы определите конечные точки и поведение службы рабочих процессов.

На рисунке 25 показано, как выглядит конструктор Visual Studio 2010 для файла Service1.xamlx. Обратите внимание, что это просто стандартный конструктор рабочих процессов. Только в этом конкретном случае рабочий процесс, который мы разрабатываем, будет служить реализацией службы WCF. Ключом к интеграции этого определения рабочего процесса с WCF является новый WorkflowServiceHost и набор действий WCF Messaging (см. панель элементов на рис. 25).

Рис. 25. Проектирование службы рабочих процессов в Visual Studio 2010

Служба шаблонного рабочего процесса, предоставляемая с этим шаблоном проекта, содержит действие Receive, за которым следует действие Send. Обратите внимание, что действие Receive содержит свойство OperationName и в настоящее время для него задано значение GetData. Он также имеет свойство Content для привязки входящего сообщения к локальной переменной, определенной в действии Sequence. В этом случае переменная называется "data" и имеет тип Int32 (см. окно Переменные под службой проектирования рабочих процессов на рис. 25).

Действие Receive также настроено для активации службы, что означает, что во входящем сообщении может быть создан новый экземпляр рабочего процесса. Обратите внимание, что свойство CanCreateInstance отмечено в окно свойств справа на рисунке 25).

Давайте немного настроим эту службу рабочих процессов. Сначала изменим имя файла службы с Service1.xamlx на HelloWorld.xamlx. Далее я изменю имя службы на "HelloWorldService" в окне надлежащего свойства. Далее я изменю свойство OperationName действия Receive на SayHello. И, наконец, я определю новую переменную с именем personName типа String в последовательности.

Затем я привяжу свойство Content действия Receive к переменной personName, как показано на рис. 26. Далее я привяжу свойство Content действия Send к строке в формате "hello {0}!" вставка переменной personName в заполнитель. Затем я сохраним полученный файл Service1.xamlx.

Рис. 26. Определение свойства Content для действия Receive

На этом этапе откройте файл HelloWorld.xamlx и проверьте его содержимое. Это можно сделать, щелкнув правой кнопкой мыши файл в Обозреватель решений и выбрав команду "Открыть с помощью..." а затем — "Редактор XML". Это позволяет просмотреть необработанное определение XAML для службы. Важно отметить, что определение XAML представляет полную реализацию службы. Код C# отсутствует.

В этом примере мы будем полагаться на конечную точку HTTP по умолчанию и предположим, что у нас есть стандартное поведение службы, которое автоматически включает метаданные службы, поэтому настройка WCF не требуется.

Теперь мы готовы протестировать службу рабочих процессов на основе XAML. Это так же просто, как нажатие клавиши F5 в Visual Studio 2010. Нажатие клавиши F5 загрузит службу рабочего процесса на сервер разработки ASP.NET и вызовет появление тестового клиента WCF. Тестовый клиент WCF автоматически подключается к службе рабочего процесса, загружает метаданные WSDL и позволяет протестировать логику службы рабочих процессов (см. рис. 27).

Рис. 27. Тестирование службы рабочих процессов

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

На этом завершается простое пошаговое руководство по созданию первой декларативной службы рабочих процессов в .NET 4. Мы увидели, что реализация службы полностью определена в XAML и что вы используете действия отправки и получения для моделирования взаимодействия обмена сообщениями в рабочем процессе. Мы также увидели, что .NET 4 поставляется с поддержкой размещения XAMLX-файлов, что устраняет необходимость в дополнительных SVC-файлах. Мы продолжим подробное изучение каждой из этих областей в следующих разделах.

Размещение службы рабочего процесса

.NET 4 поставляется с новой и улучшенной инфраструктурой размещения для служб рабочих процессов. Службы рабочих процессов можно размещать в IIS/WAS или в собственных приложениях с помощью WorkflowServiceHost. Инфраструктура размещения .NET 4 предоставляет необходимые компоненты для управления длительными экземплярами рабочих процессов и корреляции сообщений при одновременном выполнении нескольких экземпляров служб. .NET 4 также предоставляет стандартную конечную точку управления рабочим процессом для удаленного управления экземплярами рабочих процессов.

Размещение в IIS/ASP.NET

Простой пример HelloWorldWorkflowService, описанный в предыдущем разделе, проиллюстрировал размещение служб рабочих процессов в IIS/ASP.NET. Хотя мы протестировали службу с помощью сервера разработки ASP.NET, она работала бы то же самое в IIS с помощью пула приложений ASP.NET 4. .NET 4 устанавливает необходимый обработчик для запросов XAMLX, который обрабатывает создание WorkflowServiceHost в фоновом режиме и активацию отдельных экземпляров рабочего процесса.

Хотя в первом примере мы использовали подход "нулевой конфигурации", службы рабочих процессов можно настроить в Web.config как и любую другую службу WCF. Здесь можно настроить все конечные точки WCF и поведение, которые вы хотите использовать. Вы можете предоставлять любое количество конечных точек в службах рабочих процессов, но следует рассмотреть возможность использования одной из новых привязок контекста (например, BasicHttpContextBinding, WSHttpContextBinding или NetTcpContextBinding), которые управляют взаимодействием для конкретного экземпляра.

В следующем примере показано, как настроить службу рабочего процесса с двумя конечными точками HTTP:

<Конфигурации>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService">

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

      ...

Вы также можете настроить службу рабочих процессов с поведением WCF. В следующем примере показано, как настроить эту службу рабочего процесса с помощью некоторых стандартных поведений WCF:

<Конфигурации>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService"

        behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

     </Услуги>

    <Поведения>

      <serviceBehaviors>

        <behavior name="HelloWorldWorkflowService.Service1Behavior">

          <serviceDebug includeExceptionDetailInFaults="False" />

          <serviceMetadata httpGetEnabled="True"/>

        </Поведение>

      </serviceBehaviors>

      ...

Помимо этих стандартных поведений WCF, .NET 4 поставляется с некоторыми новыми поведениями WF для управления сохраняемостью рабочих процессов, отслеживанием рабочих процессов и другими поведениями среды выполнения рабочих процессов в сочетании со службами рабочих процессов. Дополнительные сведения см. в примерах пакета SDK для .NET 4.

Самостоятельное размещение с помощью WorkflowServiceHost

Хотя в .NET 3.5 был добавлен класс WorkflowServiceHost для размещения служб рабочих процессов, его необходимо было перепроектировать с учетом всех изменений среды выполнения WF и модели программирования в .NET 4. Таким образом, .NET 4 поставляется с новым классом WorkflowServiceHost, найденным в сборке System.ServiceModel.Activities.

Класс WorkflowServiceHost упрощает размещение служб рабочих процессов в собственном приложении, будь то консольное приложение, приложение WPF или служба Windows. В следующем фрагменте кода показано, как использовать WorkflowServiceHost в собственном коде приложения:

...

Узел WorkflowServiceHost = new WorkflowServiceHost("HelloWorld.xamlx",

    new Uri("https://localhost:8080/helloworld"));

Узла. AddDefaultEndpoints();

Узла. Description.Behaviors.Add(

    new ServiceMetadataBehavior { HttpGetEnabled = true });

Узла. Open();

Console.WriteLine("Узел открыт");

Console.ReadLine();

...

Как видите, независимо от того, решите ли вы разместить службы рабочих процессов в IIS/ASP.NET или в собственных приложениях, их так же легко разместить, как и любую службу WCF.

WorkflowControlEndpoint

При размещении службы рабочих процессов выполняется инициализация среды выполнения WF и активация новых экземпляров рабочего процесса при активации сообщений, поступающих через одну из предоставляемых конечных точек. В дополнение к этим базовым функциям размещения также важно иметь возможность удаленно управлять конфигурацией и выполнением этих запущенных экземпляров рабочих процессов. .NET 4 упрощает эту задачу, предоставляя стандартную точку WorkflowControlEndpoint, которую можно предоставить в службах рабочих процессов.

В следующем примере показано, как добавить стандартную конечную точку управления рабочим процессом в службу в сценарии пользовательского размещения:

...

Узел WorkflowServiceHost = new WorkflowServiceHost("HelloWorld.xamlx",

    new Uri("https://localhost:8080/helloworld"));

Узла. AddDefaultEndpoints();

WorkflowControlEndpoint wce = new WorkflowControlEndpoint(

    new NetNamedPipeBinding(),

    new EndpointAddress("net.pipe://localhost/helloworld/WCE"));

Узла. AddServiceEndpoint(wce);

Узла. Open();

...

Если вы размещаетесь в IIS/ASP.NET, вы можете добавить стандартную точку WorkflowControlEndpoint следующим образом:

<Конфигурации>

  <system.serviceModel>

    <services>

      <service name="HelloWorldWorkflowService"

          behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint address="" binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="wce" binding="wsHttpBinding" kind="workflowControlEndpoint"/>

      </service>

      ...

WorkflowControlEndpoint позволит управлять службой рабочих процессов в разных средах размещения. Одна из таких сред становится возможной благодаря Windows Server AppFabric, которая будет доступна в следующей версии Windows Server.

Действия отправки и получения

В .NET 3.5 реализовано два действия обмена сообщениями — Отправка и Получение — для отправки и получения сообщений с помощью WCF, но они были довольно ограничены с точки зрения их функциональности. .NET 4 расширяет действия отправки и получения с помощью некоторых дополнительных функций (например, корреляции) и добавляет еще несколько действий обмена сообщениями ( SendReply и ReceiveReply), которые упрощают моделирование операций запроса и ответа.

При использовании действий отправки и получения в службе рабочего процесса вы, по сути, используете их для моделирования контракта службы, который будет предоставляться клиентам через определение WSDL. При использовании действия Receive вы присвойте ему имя операции и сопоставляете входящее сообщение с типом .NET. Хотя до сих пор мы использовали простые строки, вы также можете использовать сложные контракты данных, определяемые пользователем. Давайте обновим HelloWorldWorkflowService, чтобы использовать следующий тип контракта данных:

[DataContract(Namespace="")]

public class Person

{

    [DataMember]

    идентификатор общедоступной строки;

    [DataMember]

    public string FirstName;

    [DataMember]

    public string LastName;

}

Если мы добавим это определение класса в веб-проект и вернемся к HelloWorld.xamlx, мы сможем определить новую переменную с именем personMsg типа Person (контракт данных, определенный выше). Затем можно сопоставить действия ReceiveRequest и SendResponse с переменной personMsg с помощью свойства Content. Для этого просто выберите каждое действие и нажмите кнопку "Содержимое", чтобы открыть окно "Определение содержимого". Затем введите "personMsg" в текстовом поле "Данные сообщения" и "Person" в текстовом поле "Тип сообщения". Это необходимо сделать для обоих действий.

Действия отправки и получения также позволяют настроить другие аспекты службы WCF, такие как имя операции, имя контракта службы, действие, коллекция известных типов, уровень защиты и сериализатор для использования во время выполнения (например, DataContractSerializer и XmlSerializer). В действии Отправить также укажите сведения о целевой конечной точке. Все эти параметры можно настроить с помощью окно свойств, если выбрано действие отправки и получения.

После внесения этих изменений можно снова протестировать HelloWorld.xamlx, чтобы увидеть, что операция SayHello теперь определена для получения и возврата сообщений типа Person.

Определение операций Request-Reply

Чтобы упростить моделирование операций "запрос — ответ", в .NET 4 представлено несколько новых действий для моделирования этих типов взаимодействий. Одним из них является действие SendReply, которое можно объединить с действием Receive для реализации операции "запрос—ответ" в службе. Существует также действие ReceiveReply, которое можно объединить с действием Send при вызове внешней службы в рабочем процессе.

В .NET 4 также есть несколько действий более высокого уровня, называемых ReceiveAndSendReply и SendAndReceiveReply, которые вы увидите на панели элементов Visual Studio 2010. Эти действия просто составляют получение и отправку с sendReply/ReceiveReply соответственно и упрощают их использование. При перетаскивании их в область конструктора рабочего процесса вы увидите, что они разворачиваются до последовательности, содержащей действие отправки или получения, за которым следует соответствующее действие "ответ".

Добавление ссылки на службу

Чтобы упростить работу при использовании внешних служб, Visual Studio 2010 также предоставляет функцию "Добавить ссылку на службу", которая работает так, как вы ожидаете, за исключением того, что вместо создания определения класса прокси клиента он создает набор действий на стороне клиента. После выбора параметра "Добавить ссылку на службу" и указания адреса определения WSDL Visual Studio скачивает WSDL и создает настраиваемое действие для каждой операции, найденной в определении WSDL.

Рассмотрим простой пример. Предположим, что в службе рабочих процессов имеется служба CalculatorService с операциями добавления, вычитания, умножения и деления. Можно просто выбрать "Добавить ссылку на службу" и указать расположение определения CalculatorService WSDL, как показано на рис. 28.

Рис. 28. Добавление ссылки на службу

После нажатия кнопки ОК, чтобы добавить ссылку на службу, Visual Studio скачивает определение WSDL и создает четыре настраиваемых действия, которые будут отображаться на панели элементов. Теперь у вас есть действия Add, Subtract, Multiply и Divide, которые легко использовать в рабочих процессах для вызова внешней службы.

Correlation

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

.NET 4 поставляется с сложной функцией корреляции сообщений на основе содержимого, которую можно использовать в сочетании с действиями отправки и получения, которые мы только что обсуждали. Реализация этой функции связана с так называемыми "дескрипторами корреляции", еще одной новой концепцией в .NET 4.

Чтобы начать использовать корреляцию, необходимо сначала определить переменную рабочего процесса типа CorrelationHandle. Эту переменную можно рассматривать как точку рандеву для соединения фрагмента данных из (возможно) двух разных сообщений (обрабатываемых двумя разными действиями обмена сообщениями). Действия Send и Receive предоставляют свойство CorrelationesWith для указания переменной CorrelationHandle.

Чтобы сопоставить сообщения, отправляемые несколькими действиями отправки и получения, необходимо указать один и тот же дескриптор корреляции для всех действий, которые хотят участвовать в корреляции. Затем для каждого действия настраивается ключ корреляции, который будет сопоставляться с в сообщении, обрабатываемом этим конкретным действием (например, элемент SSN в одном сообщении может коррелировать с элементом CustomerId в другом сообщении). Ключи корреляции определяются с помощью выражений XPath, которые вычисляются по сообщениям.

Давайте расширим службу HelloWorldWorkflowService, чтобы увидеть пример того, как это работает. В настоящее время пример, с которым мы работали, получает сообщение Person и возвращает его клиенту. Давайте добавим еще одно действие ReceiveAndSendReply сразу под действием SendResponse в нижней части рабочего процесса. При этом добавляется последовательность, которая содержит другое получение, за которым следует другой SendReply. Я присвою действию Receive имя операции Finish, и мы будем требовать от клиента предоставить приветствие в сообщении Finish, которое будет использоваться для создания окончательного ответа приветствия.

Другими словами, клиенты сначала вызовут SayHello, указав свое полное имя, чтобы запустить новый экземпляр службы рабочего процесса. Затем экземпляр рабочего процесса будет ждать, пока клиент не вызовет метод Finish, предоставляя приветствие (и это может занять минуты, часы или дни, в течение которых рабочий процесс может сохраниться). После того как клиент вызывает метод Finish, предоставляя приветствие, рабочий процесс создает приветствие, используя приветствие и исходное имя, и возвращает его. В этом сценарии можно легко создать несколько запущенных экземпляров рабочего процесса, ожидающих вызова операции Finish, поэтому нам, безусловно, потребуется сопоставить сообщение Finish с предыдущим сообщением SayHello. Так как это так, мне нужно связать действие Receive для "Finish" с тем же дескриптором корреляции, который мы указали в действии SayHello (nameHandle).

Теперь давайте рассмотрим содержимое сообщения, которое мы будем сопоставлять между этими двумя действиями. В этом примере я собираюсь использовать следующие два типа контрактов данных для моделирования сообщений:

[DataContract(Namespace="")]

public class Person

{

    [DataMember]

    public string FirstName { get; set; }

    [DataMember]

    public string LastName { get; set; }

}

[DataContract(Namespace = "")]

приветствие открытого класса

{

    [DataMember]

    public string Salutation { get; set; }

    [DataMember]

    public string NameKey { get; set; }

}

Действие Receive для SayHello настроено на использование сообщения Person, а действие Receive для параметра Finish — на использование приветственного сообщения. Мы предполагаем, что значение LastName всегда уникально, поэтому мы можем использовать его в качестве уникального значения для корреляции. Таким образом, когда клиент отправляет сообщение "Готово", он должен предоставить то же значение LastName, которое использовалось в предыдущем сообщении "SayHello".

Теперь давайте посмотрим, как настроить дескриптор корреляции для этой настройки. Я уже определил переменную CorrelationHandle в последовательности с именем handle. Первое, что нам нужно сделать, — это инициализировать дескриптор корреляции в действии Получения SayHello. Поэтому выберите действие "Получение SayHello" и нажмите кнопку рядом с текстовым полем CorrelationInitializers.

Здесь необходимо выбрать "Инициализатор корреляции запросов" в раскрывающемся списке, а затем вы сможете выбрать свойство LastName для поля запроса (это должно создать выражение XPath "sm:body()/xg0:Person/xg0:LastName", как показано на рисунке 29).

Затем необходимо указать, что действие "Finish" Receive с коррелирует на том же дескрипторе. Выберите действие "Готово" Получение и нажмите кнопку "КоррелироватьOn". Затем укажите "handle" для дескриптора "CorrelatesWith", а затем выберите "NameKey" в поле запроса (см. рис. 30).

Рис. 29. Определение ключа корреляции для SayHello

Рис. 30. Определение ключа корреляции для "Готово"

В конечном итоге это означает, что элемент LastName в сообщении Person должен соответствовать элементу NameKey в сообщении Greeting в двух отдельных запросах. После этого инфраструктура рабочих процессов сможет автоматически сопоставлять сообщения для нас и направлять входящие сообщения Finish в правильный экземпляр рабочего процесса (на основе LastName/NameKey).

Последнее действие SendReply возвращает вызывающей объекту следующую форматированную строку, включая сведения из исходного "personMsg" и нового "greetingMsg":

String.Format("{0}{1}{2}!",

   greetingMsg.Salutation, personMsg.FirstName, personMsg.LastName)

Я собираюсь протестировать функцию корреляции с помощью тестового клиента WCF, чтобы запустить несколько экземпляров рабочих процессов, вызвав SayHello много раз с различными значениями FirstName и LastName. После этого у нас должно быть несколько запущенных экземпляров службы рабочих процессов. Теперь можно вызвать операцию Finish, указав одно из значений LastName, используемых в одном из сообщений SayHello, и мы должны увидеть соответствующее значение FirstName, используемое в последнем приветствии, возвращенном клиенту (см. рис. 31).

Здесь показана корреляция на основе содержимого в действии, которая является привлекательной функцией служб рабочих процессов, которая поставляется с .NET 4. Важно отметить, что вы также можете выполнять корреляцию на основе данных на уровне канала и протокола, как в .NET 3.5 (например, с помощью идентификатора канала или экземпляра рабочего процесса). Корреляция на основе содержимого — это более гибкий и сложный подход к тому же.

Рис. 31. Тестирование примера корреляции на основе содержимого

Это позволяет нам завершить охват служб рабочих процессов. Мы смогли только поцарапать поверхность служб рабочих процессов в этом документе, но вы сможете найти дополнительные сведения в примерах пакета SDK для .NET 4 и в растущей документации MSDN, доступной в Интернете. Как видите, сочетание WCF и WF 4 открывает совершенно новую модель разработки для создания декларативных, длительных и асинхронных служб, которые могут пользоваться лучшими функциями обеих платформ.

Прочие расширенные функции

Помимо всего прочего, о котором мы говорили в этой статье, WCF 4 поставляется с несколькими более сложными функциями, которые могут оказаться полезными. Эти расширенные функции включают улучшенную поддержку разрешения типов с помощью DataContractResolver, возможность обработки конкурирующих потребителей очереди с помощью ReceiveContext, нового кодировщика байтового потока и высокопроизводительной трассировки на основе ETW.

Разрешение типов с помощью DataContractResolver

В WCF 3.x существует функция разрешения типов, называемая "известными типами". Во время десериализации, когда сериализатор сталкивается с экземпляром, который не относится к типу объявленного типа, он проверяет список объявленных "известных типов", чтобы выяснить, какой тип следует использовать. Как автор службы, вы можете добавлять к своим типам и методам атрибуты [KnownType] или [ServiceKnownType], чтобы определить список возможных подстановок. Эта функция обычно используется для поддержки наследования и полиморфизма.

К сожалению, WCF 3.x не предоставляет простой способ переопределить алгоритм сопоставления типов, используемый DataContractSerializer при выполнении этого типа динамического разрешения типов во время выполнения. Чтобы устранить эту проблему, WCF 4 предоставляет абстрактный класс DataContractResolver, от который можно наследовать, чтобы реализовать собственный алгоритм разрешения пользовательских типов.  Ниже показано, как приступить к работе.

класс MyDataContractResolver: DataContractResolver

{

    Сборка сборки;

    public MyDataContractResolver(сборка сборки)

    {

        this.assembly = assembly;

    }

    Используется при десериализации

    Позволяет пользователям сопоставлять xsi:type name с любым типом

    public override Type ResolveName(string typeName, string typeNamespace,

        Type declaredType, DataContractResolver knownTypeResolver)

    {

        ... // реализовать сопоставление

    }

    Используется при сериализации

    Сопоставляет любой тип с новым представлением xsi:type

    public override bool TryResolveType(Type type, Type declaredType,

        DataContractResolver knownTypeResolver, out XmlDictionaryString typeName,

        out XmlDictionaryString typeNamespace)

    {

        ... // реализовать сопоставление

    }

}

После реализации пользовательского объекта DataContractResolver его можно передать в DataContractSerializer, как показано ниже:

DataContractSerializer dcs = new DataContractSerializer(

    typeof(Object), null, int. MaxValue, false, true, null,

    новый MyDataContractResolver(assembly));

Теперь при использовании этого экземпляра DataContractSerializer для сериализации или десериализации объектов будет вызываться пользовательский dataContractResolver для выполнения разрешения пользовательского типа.

Чтобы внедрить пользовательский DataContractResolver в среду выполнения WCF в фоновом режиме, необходимо написать поведение контракта WCF, которое подключается к DataContractSerializerOperationBehavior и переопределяет сопоставитель по умолчанию. Пакет SDK для .NET 4 содержит полный пример, демонстрирующий, как это сделать с помощью поведения контракта и пользовательского атрибута с именем [KnownAssembly].

Пользовательское разрешение типов может быть полезно, если требуется переопределить значения по умолчанию DataContractSerializer, точно определить, какие типы используются для сериализации, или динамически управлять известными типами.

Обработка сообщений в очереди с помощью ReceiveContext

В WCF 3.x вы можете гарантировать ровно один раз доставку сообщений при использовании NetMsmqBinding, используя очереди транзакций и заверяя операцию службы WCF в транзакцию MSMQ. При возникновении исключений при обработке сообщения WCF гарантирует, что сообщение не будет потеряно, возвращая его в очередь (оно может быть возвращено в исходную очередь, очередь подозрительных сообщений или очередь недоставленных сообщений в зависимости от конфигурации).

Хотя эта функциональность важна, есть несколько проблем, с которыми обычно встречаются люди. Одна из них заключается в том, что транзакции являются дорогостоящими и производят много операций чтения и записи с очередями, что повышает нагрузку и сложность. Другая проблема заключается в том, что невозможно убедиться, что та же служба обрабатывает сообщение в следующий раз при извлечении из очереди (например, для определенной службы нет возможности "заблокировать" сообщение), что является гарантией, которую вы можете сделать в определенных сценариях.

Чтобы устранить эти проблемы, WCF 4 представляет новый API с именем ReceiveContext для обработки сообщений, помещенных в очередь. С помощью ReceiveContext служба может "просмотреть" сообщение в очереди, чтобы начать его обработку, и если что-то пойдет не так и возникнет исключение, оно остается в очереди. Службы могут также блокировать сообщения, чтобы еще раз попытаться обработать их позже. ReceiveContext предоставляет механизм для "завершения" сообщения после его обработки, чтобы его можно было удалить из очереди.

Такой подход упрощает работу на нескольких фронтах, так как сообщения больше не считываются и не записываются в очереди по сети, а отдельные сообщения не отправляются в разные экземпляры службы во время обработки. Давайте рассмотрим простой пример, чтобы проиллюстрировать, как это работает.

В следующем примере показано, как использовать ReceiveContext для обработки сообщений, поступающих в очередь:

...

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

[ReceiveContextEnabled(ManualControl = true)]

public void CalculateProduct(int firstNumber, int secondNumber)

{

    ReceiveContext receiveContext;

    если (! ReceiveContext.TryGet(OperationContext.Current.IncomingMessageProperties,

         out receiveContext))

    {

        Console.WriteLine("ReceiveContext не установлен или не найден на этом компьютере.");

        return;

    }

    if ((firstNumber * secondNumber) % 2 == (receiveCount % 2))

    {

        receiveContext.Complete(TimeSpan.MaxValue);

        Console.WriteLine("{0} x {1} = {2}", firstNumber, secondNumber,

            firstNumber * secondNumber);

    }

    else

    {

        receiveContext.Abandon(TimeSpan.MaxValue);

        Console.WriteLine("{0}&{1} not processed", firstNumber, secondNumber);

    }

    receiveCount++;

}

...

Предполагая успешное прохождение, мы вызываем ReceiveContext.Complete, чтобы завершить обработку сообщения, в результате чего оно будет удалено из базовой очереди. В противном случае мы вызываем команду Abandon, которая оставляет сообщение в очереди для дальнейших повторных попыток. Пакет SDK для .NET 4 содержит полный пример, который можно использовать для более подробного изучения этой новой функции.

Упрощение кодирования с помощью ByteStreamMessageEncodingBindingElement

В некоторых сценариях обмена сообщениями требуется просто передавать большие двоичные данные без какой-либо оболочки или дополнительной обработки. Чтобы упростить этот сценарий, WCF 4 поставляется с новым byteStreamMessageEncodingBindingElement, который делает именно это. К сожалению, .NET 4 не имеет новой привязки для этого кодировщика, поэтому вам придется создать пользовательскую привязку, чтобы использовать ее.

Пакет SDK для .NET 4 поставляется с полным примером, иллюстрирующий определение пользовательской привязки, использующей ByteStreamMessageEncodingBindingElement через пользовательский класс привязки. После создания нового класса привязки кодировщик потока байтов становится очень простым в использовании со службами.

Высокопроизводительная трассировка на основе трассировки на основе трассировки windows

WCF 4 также вносит некоторые улучшения в трассировку и диагностика фронте. WCF 4 теперь использует трассировку событий Windows для трассировки, что значительно повышает производительность трассировки и обеспечивает лучшую интеграцию с другими связанными технологиями, такими как Windows Workflow Foundation, Windows Server AppFabric и различными технологиями управления в Windows Server, предлагая лучшую модель для платформы.

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

Пакет SDK для .NET 4 предоставляет простой пример использования этой новой высокопроизводительной архитектуры трассировки в сочетании со службами WCF.

Заключение

WCF 4 содержит множество улучшений и несколько совершенно новых функций, которые отвечают некоторым из наиболее распространенных современных сценариев связи. В первую очередь, WCF 4 становится проще использовать благодаря упрощенной модели конфигурации и улучшенной поддержке общих значений по умолчанию.

Кроме того, WCF 4 обеспечивает первоклассную поддержку обнаружения и маршрутизации служб, которые являются общими требованиями в большинстве корпоративных сред и крупных инициатив SOA. Только эти функции отличают WCF от многих конкурирующих платформ. WCF 4 также упрощает разработку служб на основе REST и предоставляет несколько других более сложных функций WCF, которые сегодня устраняют некоторые проблемы.

В дополнение ко всему этому WCF 4 обеспечивает сложную интеграцию с WF, чтобы предоставить новую модель для разработки декларативных служб рабочих процессов. Службы рабочих процессов позволяют разрабатывать длительные и асинхронные службы, использующие модель программирования WF и базовую среду выполнения. Благодаря новым действиям на основе WCF и поддержке конструктора в Visual Studio 2010 эта новая модель программирования становится первоклассным вариантом для разработки служб.

В .NET 4 миры WCF и WF объединяются, чтобы предложить целостную модель программирования, которая дает вам лучшее, что могут предложить оба мира. Дополнительные сведения о новых возможностях WF 4 проверка в статье Введение разработчика в Windows Workflow Foundation в .NET 4.

Об авторе

Аарон Сконнард (Aaron Skonnard) является соучредителем Pluralsight, поставщика услуг обучения Майкрософт, предлагающего курсы для разработчиков .NET под руководством инструктора и по запросу. В эти дни Аарон проводит большую часть своего времени, записывая Pluralsight On-Demand! курсы, посвященные облачным вычислениям, Windows Azure, WCF и REST. Аарон провел годы в написании, выступлении и обучении профессиональных разработчиков по всему миру. Вы можете связаться с ним в http://pluralsight.com/aaron и http://twitter.com/skonnard.

Дополнительные ресурсы