Из цикла лекций «Internet-технологии разработки приложений» для студентов 4-го курса кафедры Компьютерных технологий физического факультета Донецкого национального университета проф. В. К. Толстых Расширение WCF при помощи настраиваемых поведений Расширение функциональности диспетчера сервиса и прокси клиента ДонНУ, кафедра КТ, проф.В.К.Толстых Понятие расширяемости WCF WCF предоставляет множество точек расширения своей функциональности во время выполнения, которые позволяют разработчикам настраивать поведение среды выполнения при диспетчеризации служб и при вызове прокси-клиента. Точками расширения можно воспользоваться путем декларативного (не административно в web.config) создания настраиваемых поведений службы. Среда выполнения WCF на уровне модели службы состоит из компонентов, именуемых диспетчер (на стороне службы) и прокси (на стороне клиента). Именно здесь рассмотрим расширяемость WCF. Сочетание диспетчера и прокси-клиента используется для одной цели — осуществлять преобразование между объектами сообщений WCF и вызовами методов .NET Framework (см. рис.). При выполнении этого процесса компоненты уровня модели службы выполняют строго определенную последовательность шагов и на каждом шаге предоставляют точки расширения, к которым может подключиться пользователь. Точки расширения можно использовать для реализации целого ряда настраиваемых поведений, включая проверку сообщений или параметров, ведение журнала сообщений, преобразование сообщений, пользовательские форматы сериализации/десериализации, кэширование выводимых данных, группировку объектов, обработку ошибок, авторизацию и многое другое. Архитектура среды выполнения WCF Уровень модели Уровень канала Расширения прокси-клиента 1. Точка расширения для проверки параметров. Здесь можно использовать обработчик для пользовательских проверок, изменения значений или особой фильтрации. 2. Точка настройки сериализации с помощью пользовательского объекта форматирования для преобразования любых предаваемых параметровобъектов в сообщения WCF. 3. Точка проверки объекта перед его передачей в стек канала. Здесь можно использовать обработчик для ведения журнала сообщений, проверки и преобразования. Эти расширения настраиваются в прокси-клиенте посредством объектов ClientOperation и ClientRuntime. Существует один объект ClientOperation для каждой операции службы и один объект ClientRuntime для общей настройки прокси. Расширения диспетчера 1. Точка расширения для проверки сообщения. 2. Точка расширения для переопределения поведения выбора операции, заданной по умолчанию . 3. Точка десериализации сообщения в объекты, служащие параметрами при вызове метода. Здесь можно форматировать сообщения (десериализовывать). 4. Точка проверки параметров. 5. Точка вызова метода с определенными параметрами. Этот этап можно переопределить с помощью настраиваемого объекта вызова операций. Эти расширения настраиваются в диспетчере посредством объектов DispatchRuntime и DispatchOperation. Диспетчеры В WCF существуют диспетчеры каналов (ChannelDispatcher) и конечных точек (EndpointDispatcher). Они отвечают за принятие новых каналов, получение сообщений, перенаправление и вызов операций и обработку ответов. Диспетчер каналов (и сопровождающий прослушиватель IChannelListener) удаляет сообщения из базового канала и передает их соответствующим диспетчерам конечной точки. Каждый диспетчер конечной точки имеет среду выполнения DispatchRuntime, направляющую сообщения в соответствующую операцию DispatchOperation, которая отвечает за вызов метода, реализующего операцию. Класс DispatchRuntime используется либо для изменения поведения службы по умолчанию или отдельной конечной точки, либо для вставки объектов, реализующих пользовательские изменения. Он разрешает перехватывать и расширять диспетчеры каналов или конечных точек для всех сообщений в конкретном контракте. Класс DispatchOperation — это местоположение изменений в среде выполнения и точка вставки для пользовательских расширений, область действия которых ограничивается только одной операцией службы. Изменения DispatchOperation устанавливаются с помощью пользовательского объекта поведения службы. Интерфейсы пользовательских расширений Для доступа к каждой из описанных выше точек пользовательских расширений в среде .NET имеются определенные интерфейсы: Этап Интерфейс перехватчика Описание Проверка параметров IParameterInspector Используется до и после вызова для проверки и изменения значений параметров. Форматирование сообщений IDispatchMessageFormatter IClientFormatter Используется для сериализации и десериализации. Проверка сообщений IDispatchMessageInspector IClientMessageInspector Используется до отправки и после получения для проверки и замены содержимого сообщений. Выбор операций IDispatchOperationSelector IClientOperationSelector Используется для выбора вызываемой операции для определенного сообщения. Вызов операции IOperationInvoker Используется для вызова операции. Инспектор параметров IParameterInspector Например, перед вызовом операции можно проконтролировать её параметры. Для этого надо создать класс реализации интерфейса IParameterInspector. Он должен содержать два методы AfterCall и BeforeCall: public class MyParameterInspector : IParameterInspector { public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) { } } // Пустой метод public object BeforeCall(string operationName, object[] inputs) { for (int i = 0; i < inputs.Length; i++) { // Контроль параметров inputs[i] текущей операции } return null; } Теперь данный класс необходимо подключить к среде выполнения посредством создания нового класса, расширяющего поведение среды во время инициализации конструкторов ServiceHost или ChannelFactory (см. далее) Применение пользовательских расширений с помощью поведений Поведение — это особый тип класса, расширяющий поведение среды во время инициализации конструкторов ServiceHost/ChannelFactory. Существует четыре типа поведений с соответствующими интерфейсами : Служба — IServiceBehavior, конечная точка — IEndpointBehavior, контракт — IEndpointBehavior, операция — IOperationBehavior, Каждый тип поведения используют один и тот же набор методов: Метод Описание Validate Используется непосредственно перед построением среды выполнения — позволяет осуществлять пользовательскую проверку описания службы. AddBindingParameters Используется на первом этапе построения среды выполнения до построения базового канала — позволяет добавлять параметры для изменения стека базового канала. ApplyClientBehavior Позволяет поведению включать расширения прокси (клиента). Данный метод недоступен для IServiceBehavior. ApplyDispatchBehavior Позволяет поведению включать расширения диспетчера. Поведение операций IOperationBehavior Например, для добавления расширений операций MyParameterInspector будем использовать интерфейс поведения операций IOperationBehavior для диспетчера – DispatchOperation. Создадим необходимый атрибут контракта операции, добавляющий нужное поведение : public class MyOperatioinValidation : Attribute, IOperationBehavior { public void ApplyDispatchBehavior (OperationDescription operationDescription, DispatchOperation dispatchOperation) { dispatchOperation.ParameterInspectors.Add(new MyParameterInspector()); } ... // остальные методы - пустые } Теперь необходимо указать данный атрибут в соответствующем контракте: [ServiceContract] public interface MyService { [MyOperatioinValidation] [OperationContract] string MyOperation(…); } Пример 1: Объединение в одном классе пользовательских расширений и поведений // «Прослушивание» операций: public class OperationListener : Attribute, IOperationBehavior, IParameterInspector { public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) {} public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) {} public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { dispatchOperation.ParameterInspectors.Add(this); } public void Validate(OperationDescription operationDescription) {} //------------- Методы инспектора параметров IParameterInspector ---------------// public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) {} public object BeforeCall(string operationName, object[] inputs) { for (int i = 0; i < inputs.Length; i++) { /* Контроль параметров inputs[i] текущей операции */ } return null; } } Пример 2: Объединение в одном классе пользовательских расширений и поведений // «Прослушивание» конечных точек и сервисов: public class ServicePointListener: Attribute, IEndpointBehavior, IServiceBehavior { void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher eDispatcher) { eDispatcher.DispatchRuntime.MessageInspectors.Add(new MyMessageInspector()); } // ... остальные методы void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host) { foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers) foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints) eDispatcher.DispatchRuntime.MessageInspectors.Add(new MyMessageInspector()); } //------------- Класс с методами инспектора сообщений ---------------// public class MyMessageInspector : Attribute, IDispatchMessageInspector { //Разрешает проверку или изменение сообщения public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { //Реализация метода return null; } public void BeforeSendReply(ref Message reply, object correlationState) {} } … продолжение Прослушиватели конечных точек и сервисов подключаются как атрибут сервиса: [ServicePointListener] public class MyService : IMyService { … } После создания конструктора ServiceHost или клиентского конструктора ChannelFactory среда выполнения отражает типы служб, выполняет чтение файла конфигурации и приступает к созданию описания службы в памяти системы. В ServiceHost описание доступно посредством свойства Description (тип ServiceDescription). В ChannelFactory описание доступно посредством свойства Endpoint (тип ServiceEndpoint); описание на стороне клиента ограничено целевой конечной точкой. ServiceDescription содержит полное описание службы и каждой конечной точки (ServiceEndpoint), включая контракты (ContractDescription) и операции (OperationDescription). ServiceDescription предоставляет свойство Behaviors (коллекцию типа IServiceBehavior), которое моделирует коллекцию поведений службы. Каждая конечная точка ServiceEndpoint также имеет свойство Behaviors (коллекцию типа IEndpointBehavior), которое моделирует отдельные поведения конечной точки. Аналогичным образом, ContractDescription и OperationDescription имеют соответствующее свойство Behaviors. Эти коллекции поведений автоматически заполняются во время создания ServiceHost и ChannelFactory любыми поведениями, найденными в коде (посредством атрибутов) или в файле конфигурации. Источники • MSDN. Расширение WCF [Электронный ресурс] / URL: http://msdn.microsoft.com/ru-ru/library/ms733848.aspx • Аарон Сконнард. Расширение WCF при помощи настраиваемых поведений. - Журнал MSDN Magazine [Электронный ресурс] / URL: http://msdn.microsoft.com/ru-ru/magazine/cc163302.aspx