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 }
參考資料
文章列表