OperationInvoker 介绍

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

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

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

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

IOperationInvoker 接口定义

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

问题描述

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

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

   public class UnityContainerScope : IDisposable
{
public static UnityContainerScope NewScope()
{
return new UnityContainerScope();
} public void Dispose()
{ }
}

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

   public class CalculatorService : ICalculatorService
{
public int Add(int a, int b)
{
using (var scope = UnityContainerScope.NewScope())
{
return a + b;
}
}
}

解决方案

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

   public class UnityContainerScopeOperationInvoker : IOperationInvoker
{
private IOperationInvoker originalInvoker; public UnityContainerScopeOperationInvoker(IOperationInvoker originalInvoker)
{
this.originalInvoker = originalInvoker;
} #region IOperationInvoker Members public object[] AllocateInputs()
{
return this.originalInvoker.AllocateInputs();
} public object Invoke(object instance, object[] inputs, out object[] outputs)
{
using (var scope = UnityContainerScope.NewScope())
{
return this.originalInvoker.Invoke(instance, inputs, out outputs);
}
} public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return this.originalInvoker.InvokeBegin(instance, inputs, callback, state);
} public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return this.originalInvoker.InvokeEnd(instance, out outputs, result);
} public bool IsSynchronous
{
get { return this.originalInvoker.IsSynchronous; }
} #endregion
}

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

   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public sealed class UnityContainerScopeOperationBehaviorAttribute : Attribute, IOperationBehavior
{
#region IOperationBehavior Members public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
} public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
if (dispatchOperation != null)
{
dispatchOperation.Invoker = new UnityContainerScopeOperationInvoker(dispatchOperation.Invoker);
}
} public void Validate(OperationDescription operationDescription)
{
} #endregion
}

使用方式:

   [ServiceContract]
public interface ICalculatorService
{
[OperationContract]
[UnityContainerScopeOperationBehavior]
int Add(int a, int b);
}

扩展实现

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

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

   public class UnityContainerScopeEndpointBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
if (endpoint != null)
{
foreach (var operation in endpoint.Contract.Operations)
{
bool hasAdded = false; foreach (var item in operation.Behaviors)
{
if (item.GetType().FullName == typeof(UnityContainerScopeOperationBehaviorAttribute).FullName)
{
hasAdded = true;
break;
}
} if (!hasAdded)
{
operation.Behaviors.Add(new UnityContainerScopeOperationBehaviorAttribute());
}
}
}
} public void Validate(ServiceEndpoint endpoint)
{
} #endregion
}

参考资料

真实世界:使用WCF扩展在方法调用前初始化环境的更多相关文章

  1. 使用WCF扩展在方法调用前初始化环境

    使用WCF扩展在方法调用前初始化环境 OperationInvoker 介绍 OperationInvoker 是 WCF 运行时模型中在调用最终用户代码前的最后一个扩展点,OperationInvo ...

  2. 真实世界:使用WCF扩展记录服务调用时间

    WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...

  3. 使用WCF扩展记录服务调用时间

    随笔- 64  文章- 0  评论- 549  真实世界:使用WCF扩展记录服务调用时间   WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Lay ...

  4. WCF扩展记录服务调用时间

    WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服务模型层(Serv ...

  5. 使用spring框架进行aop编程实现方法调用前日志输出

    aop编程 之使用spring框架实现方法调用前日志输出 使用spring框架实现AOP编程首先需要搭建spring框架环境: 使用Spring框架实现AOP工程编程之后,不需要我们去写代理工厂了,工 ...

  6. WCF扩展

    WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...

  7. Spring @Cacheable注解 && 事务@Transactional 在同一个类中的方法调用不生效

    @Cacheable 注解在对象内部调用不会生效 代码示例:ProductServiceImpl.java public List<ProductInfoVO> getProductLis ...

  8. java方法调用及传参

    静态方法:有static修饰的方法. 非静态方法:没有static修饰的方法. 方法调用: 一静态方法调用 静态方法/属性 1)一个类:直接调用. 2)不同类/不同文件: a: 类名.属性名/方法名 ...

  9. 实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法

    关于ajax跨域调用WCF服务的方法很多,经过我反复的代码测试,认为如下方法是最为简便的,当然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义还是延用上次的,如: namespace Wcf ...

随机推荐

  1. 文件读写方法1.FileInputStream和FileOutputStream

    package fileTest; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  2. Hibernate之jpa实体映射的三种继承关系

    在JPA中,实体继承关系的映射策略共有三种:单表继承策略(table per class).Joined策略(table per subclass)和Table_PER_Class策略. 1.单表继承 ...

  3. vbs获取命令行里的参数

    var args1=WScript.Arguments.Item(0) var args2=WScript.Arguments.Item(1)

  4. UVa 10071 - Back to High School Physics

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=s ...

  5. JQuery中ajax请求写法

    $.ajax({ type: "POST", url: "ygdwController.do?getonygdw", data : "id=" ...

  6. Linux内核分析第二周学习总结:操作系统是如何工作的?

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.函数调用堆栈 ...

  7. vs2015连接oracle 11g(.net自带方式 using System.Data.OracleClient;)

    1,添加引用 System.Data.OracleClient 2,连接语句 string connectionString; string queryString; connectionString ...

  8. 关于Oracle的性能调整(一)

    Oracle Tuning的一些总结 关于Oracle的性能调整,一般包括两个方面,一是指Oracle数据库本身的调整,比如SGA.PGA的优化设置,二是连接Oracle的应用程序以及SQL语句的优化 ...

  9. NLPP-00-Preparation

    NLPP is short for Natural Language Processing with Python <Python 自然语言处理(Natural Language Process ...

  10. iOS定位到崩溃代码行数

    不知道大家是不是在代码调试过程中经常遇到项目崩溃的情况: 比如: 数组越界: 没有实现方法选择器: 野指针: 还有很多很多情况.......昨天学到了一种可以直接定位到崩溃代码行数的一个命令,记录一下 ...