现在的位置: 首页 > 综合 > 正文

WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成

2011年05月02日 ⁄ 综合 ⁄ 共 5530字 ⁄ 字号 评论关闭

上一篇文章中,我们通过自定义InstanceProvider实现了WCF和微软Enterprise Library Unity Application Block的集成, 今天我们已相同的方式实现WCF与Enterprise Library的另一个Application Block的集成:Policy Injection Application Block (PIAB)。

PIAB,通过Method Interception的机制实现了AOP(Aspect Oriented Programing)。按照PIAB的编程方式,我们将非业务逻辑,比如Caching、Authorization、Transaction Enlist、Auditing、ExceptionHandling扽等等, 定义在一个个的CallHandler,这些CallHandler通过Attribute或者Configuration的方式应用到目标方法上。关于PIAB的详细介绍,我们参考我的PIAB系列(http://www.cnblogs.com/artech/archive/2008/01/29/1057379.html)。

由于PIAB特殊的实现机制(PIAB实现原理),我们需要通过PIAB的PolicyInjector来创建新的对象或者包装现有的目标对象。只有调用这种能够方式的对象,应用在上面的CallHandler才能被执行。所以WCF和PIAB的核心问题就是如何通过PIAB PolicyInjector来创建新的Service Instance,或者包装已经生成的service instance。在上面一篇文章中,我们通过Unity Container重新定义了InstanceProvider,我们今天的实现方案也是通过自定义InstanceProvider的方式来实现,不是我们需需要通过PolicyInjector来进行对象的创建。

一、创建基于PolicyInjection的InstanceProvider

下面是我们新的InstanceProvider(PolicyInjectionInstanceProvider )的定义

   1: namespace Artech.WCFExtensions

   2: {

   3:     public class PolicyInjectionInstanceProvider : IInstanceProvider

   4:     {

   5:         private Type _serviceContractType;

   6:         private string _policyInjectorName;

   7:  

   8:         public PolicyInjectionInstanceProvider(Type serviceContractType, string policyInjectorName)

   9:         {

  10:             this._serviceContractType = serviceContractType;

  11:             this._policyInjectorName = policyInjectorName;

  12:         }

  13:         public object GetInstance(InstanceContext instanceContext, Message message)

  14:         {

  15:             PolicyInjector policyInjector = null;

  16:             if (string.IsNullOrEmpty(this._policyInjectorName))

  17:             {

  18:                 policyInjector = new PolicyInjectorFactory().Create();

  19:             }

  20:             else

  21:             {

  22:                 policyInjector = new PolicyInjectorFactory().Create(this._policyInjectorName);

  23:             }

  24:  

  25:             Type serviceType = instanceContext.Host.Description.ServiceType;

  26:             object serviceInstance = Activator.CreateInstance(serviceType);

  27:             if (!this._serviceContractType.IsInterface && !serviceType.IsMarshalByRef && policyInjector is RemotingPolicyInjector)

  28:             {

  29:                 return serviceInstance;

  30:             }

  31:  

  32:             return policyInjector.Wrap(serviceInstance, this._serviceContractType);

  33:         }

  34:  

  35:         public object GetInstance(InstanceContext instanceContext)

  36:         {

  37:             return this.GetInstance(instanceContext, null);

  38:         }

  39:  

  40:         public void ReleaseInstance(InstanceContext instanceContext, object instance)

  41:         {

  42:             IDisposable disposable = instance as IDisposable;

  43:             if (disposable != null)

  44:             {

  45:                 disposable.Dispose();

  46:             }

  47:         }

  48:     }

  49: } 

我们对PolicyInjectionInstanceProvider 的实现进行简单的说明:在PIAB中真正用于创建对象的是PolicyInjector,虽然PIAB中仅仅定义了一种基于Remoting的RemotingPolicyInjector,但是我们可以根据我们的需要实现一些不同Injection方式,比如IL Injection。所以我们定义了一个字段_policyInjectorName在配置中定位我们需要的PolicyInjector。该字段如果为null或者empty,将使用默认的PolicyInjector。PolicyInjection的获取通过下面的代码实现:

   1: PolicyInjector policyInjector = null;

   2: if (string.IsNullOrEmpty(this._policyInjectorName))

   3: {

   4:     policyInjector = new PolicyInjectorFactory().Create();

   5: }

   6: else

   7: {

   8:     policyInjector = new PolicyInjectorFactory().Create(this._policyInjectorName);

   9: } 

能够被RemotingPolicyInjector创建的对象不是满足下面两个条件中的一个:

  • Target type实现一个Interface。
  • Target Type直接或者间接集成System.MarshalByRefObject.

所以如果不能满足这个条件,我们直接通过反射创建service instance:

   1: Type serviceType = instanceContext.Host.Description.ServiceType;

   2: object serviceInstance = Activator.CreateInstance(serviceType);

   3: if (!this._serviceContractType.IsInterface && !serviceType.IsMarshalByRef && policyInjector is RemotingPolicyInjector)

   4: {

   5:          return serviceInstance;

   6: } 

最后我们通过policyInjector 的Wrap方法对service instance进行封装并返回:

   1: return policyInjector.Wrap(serviceInstance, this._serviceContractType);

二、为PolicyInjectionInstanceProvider创建Behavior

我们可以通过ContractBehavior或者EndpointBehavior应用我们定义的PolicyInjectionInstanceProvider 。

I、ContractBehavior:PolicyInjectionBehaviorAttribute

   1: namespace Artech.WCFExtensions

   2: {

   3:     public class PolicyInjectionBehaviorAttribute : Attribute, IContractBehavior

   4:     {

   5:         public string PolicyInjectorName{ get; set; }

   6:         public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){ }

   7:         public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime){ }

   8:         public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)

   9:         {

  10:             Type serviceContractType = contractDescription.ContractType;

  11:             dispatchRuntime.InstanceProvider = new PolicyInjectionInstanceProvider(serviceContractType, this.PolicyInjectorName);

  12:         }

  13:         public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint){ 

  14:     }

  15: } 

我们在ApplyDispatchBehavior,通过contractDescription.ContractType获得service contract type,然后创建我们的PolicyInjectionInstanceProvider, 并将其指定成当前DispatchRuntime 的InstanceProvider 。PolicyInjector通过属性PolicyInjectorName进行设置。

II、Endpoint Behavior & Behavior Extension: PolicyInjectionBehavior

   1: namespace Artech.WCFExtensions

   2: {

   3:     public class PolicyInjectionBehavior : IEndpointBehavior

   4:     {

   5:         private string _policyInjectorName;

   6:         public PolicyInjectionBehavior(string policyInjectorName)

   7:         {

   8:             this._policyInjectorName = policyInjectorName;

   9:         }

  10:         public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){ }

  11:         public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime){ }

  12:         public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)

  13:         {

  14:             Type serviceContractType = endpoint.Contract.ContractType;

  15:             endpointDispatcher.DispatchRuntime.InstanceProvider = new PolicyInjectionInstanceProvider(serviceContractType, this._policyInjectorName);

  16:         }

  17:         public void Validate(ServiceEndpoint endpoint){ }

  18:     }

  19: } 

当前DispatchRuntime的InstanceProvider 在ApplyDispatchBehavior方法中指定,PolicyInjectorName通过配置文件配置。该配置节通过下面的PolicyInjectionBehaviorElement定义:

   1: namespace Artech.WCFExtensions

   2: {

   3:     

【上篇】
【下篇】

抱歉!评论已关闭.