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. fastreport 如何 设置 richview 的 行高

    richview中的行高改变有点特别.必须在AfterData 事件执行的时候才能修改: 也就是说,如果简单的放一个按钮,去发送消息给richView->RichEdit ,然后调用frxRep ...

  2. archlinux更新错误

    问题1 初始化下载: http://repo.archlinuxcn.org/x86_64/wps-office-10.1.0.5672_a21-2-x86_64.pkg.tar.xz 文件大小: 1 ...

  3. Icinga快速安装与配置

    Icinga快速安装与配置/* body */body { margin: 20px; padding: 0; font-family: "Lucida Grande", &quo ...

  4. windows下安装多个tomcat服务

    摘要 公司服务器已经部署2个tomcat,分别属于不同的系统.今天新开发的系统也要上线测试,故新增一个tomcat服务器. 1.官网下载tomcat 7 解压缩版本.我使用的是 apache-tomc ...

  5. 信息安全系统设计基础课程实践:简单TUI游戏设计

    简单TUI游戏设计                目       录               一                      Curses库简介与基本开发方法             ...

  6. WebView加载本地Html文件并实现点击效果

    Webview是用来与前端交互的纽,可以加载本地Html文件,和网页并实现交互的功能. WebView通过WebSetting可以使用Android原生的JavascriptInterface来进行j ...

  7. 在Linux终端命令行下播放音乐的命令(Ubuntu)

    现在的 Linux 桌面已经发展的很好了,在桌面下播放音乐操作起来也很简单.那么我们还记得在桌面不是那么好的时候我们是怎么播放音乐的么?哎,我是想不起来了,实在是太难了. 不过现在我们可以先安装一个小 ...

  8. MATLAB - 练习程序,直方图均衡化

    直方图均衡化的作用是图像增强. 有两个问题比较难懂,一是为什么要选用累积分布函数,二是为什么使用累积分布函数处理后像素值会均匀分布. 第一个问题.均衡化过程中,必须要保证两个条件:①像素无论怎么映射, ...

  9. c语言中enum类型的用法

    11.10 枚举类型 在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量说明为整型,字符型或其它类型显然是不妥当的 ...

  10. 在html里添加视频的方法

    在html里添加本地视频的方法: <!DOCTYPE HTML><html><body><video width="320" height ...