文章出處

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   }

 

參考資料

 


文章列表


不含病毒。www.avast.com
全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()