真实世界:使用WCF扩展在方法调用前初始化环境
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扩展在方法调用前初始化环境的更多相关文章
- 使用WCF扩展在方法调用前初始化环境
使用WCF扩展在方法调用前初始化环境 OperationInvoker 介绍 OperationInvoker 是 WCF 运行时模型中在调用最终用户代码前的最后一个扩展点,OperationInvo ...
- 真实世界:使用WCF扩展记录服务调用时间
WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...
- 使用WCF扩展记录服务调用时间
随笔- 64 文章- 0 评论- 549 真实世界:使用WCF扩展记录服务调用时间 WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Lay ...
- WCF扩展记录服务调用时间
WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服务模型层(Serv ...
- 使用spring框架进行aop编程实现方法调用前日志输出
aop编程 之使用spring框架实现方法调用前日志输出 使用spring框架实现AOP编程首先需要搭建spring框架环境: 使用Spring框架实现AOP工程编程之后,不需要我们去写代理工厂了,工 ...
- WCF扩展
WCF 可扩展性 WCF 提供了许多扩展点供开发人员自定义运行时行为. WCF 在 Channel Layer 之上还提供了一个高级运行时,主要是针对应用程序开发人员.在 WCF 文档中,它常被称为服 ...
- Spring @Cacheable注解 && 事务@Transactional 在同一个类中的方法调用不生效
@Cacheable 注解在对象内部调用不会生效 代码示例:ProductServiceImpl.java public List<ProductInfoVO> getProductLis ...
- java方法调用及传参
静态方法:有static修饰的方法. 非静态方法:没有static修饰的方法. 方法调用: 一静态方法调用 静态方法/属性 1)一个类:直接调用. 2)不同类/不同文件: a: 类名.属性名/方法名 ...
- 实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法
关于ajax跨域调用WCF服务的方法很多,经过我反复的代码测试,认为如下方法是最为简便的,当然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义还是延用上次的,如: namespace Wcf ...
随机推荐
- fastreport 如何 设置 richview 的 行高
richview中的行高改变有点特别.必须在AfterData 事件执行的时候才能修改: 也就是说,如果简单的放一个按钮,去发送消息给richView->RichEdit ,然后调用frxRep ...
- archlinux更新错误
问题1 初始化下载: http://repo.archlinuxcn.org/x86_64/wps-office-10.1.0.5672_a21-2-x86_64.pkg.tar.xz 文件大小: 1 ...
- Icinga快速安装与配置
Icinga快速安装与配置/* body */body { margin: 20px; padding: 0; font-family: "Lucida Grande", &quo ...
- windows下安装多个tomcat服务
摘要 公司服务器已经部署2个tomcat,分别属于不同的系统.今天新开发的系统也要上线测试,故新增一个tomcat服务器. 1.官网下载tomcat 7 解压缩版本.我使用的是 apache-tomc ...
- 信息安全系统设计基础课程实践:简单TUI游戏设计
简单TUI游戏设计 目 录 一 Curses库简介与基本开发方法 ...
- WebView加载本地Html文件并实现点击效果
Webview是用来与前端交互的纽,可以加载本地Html文件,和网页并实现交互的功能. WebView通过WebSetting可以使用Android原生的JavascriptInterface来进行j ...
- 在Linux终端命令行下播放音乐的命令(Ubuntu)
现在的 Linux 桌面已经发展的很好了,在桌面下播放音乐操作起来也很简单.那么我们还记得在桌面不是那么好的时候我们是怎么播放音乐的么?哎,我是想不起来了,实在是太难了. 不过现在我们可以先安装一个小 ...
- MATLAB - 练习程序,直方图均衡化
直方图均衡化的作用是图像增强. 有两个问题比较难懂,一是为什么要选用累积分布函数,二是为什么使用累积分布函数处理后像素值会均匀分布. 第一个问题.均衡化过程中,必须要保证两个条件:①像素无论怎么映射, ...
- c语言中enum类型的用法
11.10 枚举类型 在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量说明为整型,字符型或其它类型显然是不妥当的 ...
- 在html里添加视频的方法
在html里添加本地视频的方法: <!DOCTYPE HTML><html><body><video width="320" height ...