zoukankan      html  css  js  c++  java
  • 使用WCF扩展在方法调用前初始化环境

    使用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   }
    复制代码

    参考资料

  • 相关阅读:
    Eclipse快捷键 10个最有用的快捷键
    Eclipse--Web项目中 .classpath、mymetadata、project文件的功用
    java.lang.IllegalStateException:Web app root system property already set to different value 错误原因及解决 Log4j
    验证位置时发生错误:“org.tigris.subversion.javahl.ClientException......
    隐藏控制台黑窗口
    APK伪加密
    格蠹汇编-01-blog
    static_cast、dynamic_cast、const_cast和reinterpret_cast总结
    CONTAINING_RECORD宏
    explicit关键字
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3367275.html
Copyright © 2011-2022 走看看