真实世界:使用WCF扩展在方法调用前初始化环境

OperationInvoker 介绍

OperationInvoker 是 WCF 运行时模型中在调用最终用户代码前的最后一个扩展点,OperationInvoker 负责最终调用 Service Operation,并且在 IOperationInvoker 中定义了操作调用的同步和异步模式。

在 WCF 的内部,实现了同步和异步的方法调用类:

  • System.ServiceModel.Dispatcher.SyncMethodInvoker
  • System.ServiceModel.Dispatcher.AsyncMethodInvoker

上述两个实现是方法调用的默认实现。

IOperationInvoker 接口定义

 1   // Summary:
 2   //     Declares methods that take an object and an array of parameters extracted
 3   //     from a message, invoke a method on that object with those parameters, and
 4   //     return the method's return value and output parameters.
 5   public interface IOperationInvoker
 6   {
 7     bool IsSynchronous { get; }
 8     object[] AllocateInputs();
 9     object Invoke(object instance, object[] inputs, out object[] outputs);
10     IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state);
11     object InvokeEnd(object instance, out object[] outputs, IAsyncResult result);
12   }

问题描述

现在,我们需要在每个服务操作调用前为其单独准备 UnityContainer 环境,目的是保证每个服务操作调用所在的线程使用唯一个 UnityContainer。

假设,设计一个 UnityContainerScope 类来完成此工作。

 1   public class UnityContainerScope : IDisposable
 2   {
 3     public static UnityContainerScope NewScope()
 4     {
 5       return new UnityContainerScope();
 6     }
 7 
 8     public void Dispose()
 9     {
10      
11     }
12   }

则服务实现中需要为每个操作添加 using (var scope = UnityContainerScope.NewScope()) {} 来完成 Scope 初始化。

 1   public class CalculatorService : ICalculatorService
 2   {
 3     public int Add(int a, int b)
 4     {
 5       using (var scope = UnityContainerScope.NewScope())
 6       {
 7         return a + b;
 8       }
 9     }
10   }

解决方案

通过实现 IOperationInvoker 接口,在指定的 Operation 调用前直接调用 UnityContainerScope (仅实现同步接口调用) 。

 1   public class UnityContainerScopeOperationInvoker : IOperationInvoker
 2   {
 3     private IOperationInvoker originalInvoker;
 4 
 5     public UnityContainerScopeOperationInvoker(IOperationInvoker originalInvoker)
 6     {
 7       this.originalInvoker = originalInvoker;
 8     }
 9 
10     #region IOperationInvoker Members
11 
12     public object[] AllocateInputs()
13     {
14       return this.originalInvoker.AllocateInputs();
15     }
16 
17     public object Invoke(object instance, object[] inputs, out object[] outputs)
18     {
19       using (var scope = UnityContainerScope.NewScope())
20       {
21         return this.originalInvoker.Invoke(instance, inputs, out outputs);
22       }
23     }
24 
25     public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
26     {
27       return this.originalInvoker.InvokeBegin(instance, inputs, callback, state);
28     }
29 
30     public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
31     {
32       return this.originalInvoker.InvokeEnd(instance, out outputs, result);
33     }
34 
35     public bool IsSynchronous
36     {
37       get { return this.originalInvoker.IsSynchronous; }
38     }
39 
40     #endregion
41   }

通过实现 UnityContainerScopeOperationBehaviorAttribute 来为需要初始化 Scope 的 Operation 进行定制。

 1   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
 2   public sealed class UnityContainerScopeOperationBehaviorAttribute : Attribute, IOperationBehavior
 3   {
 4     #region IOperationBehavior Members
 5 
 6     public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
 7     {
 8     }
 9 
10     public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
11     {
12     }
13 
14     public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
15     {
16       if (dispatchOperation != null)
17       {
18         dispatchOperation.Invoker = new UnityContainerScopeOperationInvoker(dispatchOperation.Invoker);
19       }
20     }
21 
22     public void Validate(OperationDescription operationDescription)
23     {
24     }
25 
26     #endregion
27   }

使用方式:

1   [ServiceContract]
2   public interface ICalculatorService
3   {
4     [OperationContract]
5     [UnityContainerScopeOperationBehavior]
6     int Add(int a, int b);
7   }

扩展实现

当然,通常定义 Contracts 的程序集比较纯粹干净,不会有多于的类库引用。而如果 UnityContainerScopeOperationBehaviorAttribute 定义在其他类库中,比如通用类库,则 Contracts 程序集则必须引用该类库。

我们可以通过使用 IEndpointBehavior 来进行行为扩展,而无需在每个 OperationContract 定义上 HardCode 。

 1   public class UnityContainerScopeEndpointBehavior : IEndpointBehavior
 2   {
 3     #region IEndpointBehavior Members
 4 
 5     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
 6     {
 7     }
 8 
 9     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
10     {
11     }
12 
13     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
14     {
15       if (endpoint != null)
16       {
17         foreach (var operation in endpoint.Contract.Operations)
18         {
19           bool hasAdded = false;
20 
21           foreach (var item in operation.Behaviors)
22           {
23             if (item.GetType().FullName == typeof(UnityContainerScopeOperationBehaviorAttribute).FullName)
24             {
25               hasAdded = true;
26               break;
27             }
28           }
29 
30           if (!hasAdded)
31           {
32             operation.Behaviors.Add(new UnityContainerScopeOperationBehaviorAttribute());
33           }
34         }
35       }
36     }
37 
38     public void Validate(ServiceEndpoint endpoint)
39     {
40     }
41 
42     #endregion
43   }

 

参考资料

 

posted @ 2013-10-13 14:13  sangmado  阅读(2098)  评论(1编辑  收藏  举报