Итак, предже чем приступить к реализации наметим основные шаги:
- Для начала создадим простой WCF сервис
- Реализуем свой IInstanceProvider
- Далее опишем собственную реализацию IServiceBehavior
- Определим BehaviorExtensionElement
- И закончим, добавив необходимые настройки в web.config
Шаг 1.Создадим новый WCF проект, назовем его WcfService, с контрактом в виде интерфейса:
[ServiceContract]
public interface IHelloService
{
[OperationContract]
string Say(string name);
}
Реализуем данный интерфейс в виде класса, с осуществлением инъекции (injection) в виде типа IEnveloper в конструктор:
public class HelloService : IHelloService
{
IEnveloper _enveloper;
// Инъекция типа IEnveloper в конструктор
public HelloService(IEnveloper enveloper)
{
_enveloper = enveloper;
}
public string Say(string name)
{
string data = string.Format("Hello, {0}", name);
return _enveloper.Envelop(data);
}
}
Шаг 2.За создание экземпляра IHelloService отвечает IInstanceProvider, но стандартный IInstanceProvider не умеет делать инъекции, поэтому необходимо реализовать свой, для этого добавляем следующий класс:
public class UnityInstanceProvider : IInstanceProvider
{
IUnityContainer _container;
Type _serviceType;
public UnityInstanceProvider(IUnityContainer container, Type serviceType)
{
_serviceType = serviceType;
_container = container;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
// Я не использую здесь информацию message, хотя можно
// разрешать типы на основе полей (или заголовков)
// содержащиеся в message.
return GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
// Здесь происходит разрешение типа, со всеми инъекциями.
return _container.Resolve(_serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
// Так как тип породил контейнер, он же его и разрушает.
_container.Teardown(instance);
}
}
Шаг 3.UnityInstanceProvider готов, но стандартное поведение(behavior) использует страндартный InstanceProvider, и для того чтобы сообщить среде, что надо использовать наш UnityInstanceProvider нужно реализовать свое поведение (behavior):
public class UnityServiceBehavior : IServiceBehavior
{
IUnityContainer _container;
public UnityServiceBehavior(IUnityContainer container)
{
_container = container;
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var cdb in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (var ed in cd.Endpoints)
{
// Тип нашего сервиса
Type serviceType = serviceDescription.ServiceType;
// Подготовим провайдер.
// Хотя провайдер сам бы мог строить контейнер в себе,
// но лучше иметь один контейнер на всех.
IInstanceProvider provider = new UnityInstanceProvider(_container, serviceType);
// Укажем среде использовать наш провайдер.
ed.DispatchRuntime.InstanceProvider = provider;
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
Шаг 4.Осталось наделить наш новый WCF сервис нашим новым поведением UnityServiceBehavior. Это можно сделать как и в коде, так и через web.config (что удобнее). Так как UnityServiceBehavior является по сути расширением, и чтобы опледелить его в настройках (web.config) необходимо определить для него элемент конфигурации:
public class UnityServiceBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(UnityServiceBehavior); }
}
protected override object CreateBehavior()
{
IUnityContainer container = new UnityContainer();
// Настраивать конечно лучше в конфигурационном
// файле, но так будет быстрее и надежнее.
container.RegisterType<IEnveloper, XmlEnveloper>();
return new UnityServiceBehavior(container);
}
}
где XmlEnveloper одна из возможных реализаций IEnveloper:
public class XmlEnveloper : IEnveloper
{
public string Envelop(string data)
{
return string.Format("<result>{0}</result>", data);
}
}
Шаг 4.Наделяем наш WCF сервис новым поведением, делается это просто в web.config.
Регистрируем расширение в секции extensions:
<extensions>
<behaviorExtensions>
<add name="serviceInjection" type="WcfService.UnityServiceBehaviorExtensionElement, WcfService"/>
</behaviorExtensions>
</extensions>
Добавляем поведение serviceInjection в секцию behavior:
<behaviors>
<serviceBehaviors>
<behavior>
.
.
<serviceInjection/>
.
.
</behavior>
</serviceBehaviors>
</behaviors>
Сервис готов!
Интересная статья, когда то очень нужно было в диплом прикрутить инверсию в WCF, но так и не нашел подходящего решения, теперь буду знать, СПАСИБО!
ОтветитьУдалить