真实世界:使用WCF扩展在方法调用前初始化环境
2013-10-13 14:13
393 查看
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 Extensibility – IOperationInvoker相关文章推荐
- 使用WCF扩展在方法调用前初始化环境
- 真实世界:使用WCF扩展记录服务调用时间
- WCF使用地址去调用服务端的方法
- 一个关于WCF调用远程链接返回405错误不允许使用此方法的问题
- ice环境初始化和slice方法调用
- java 程序加载过程---3--类中申明同时申明类的静态对象 创建类的实例 访问类的静态变量 调用类的静态方法 使用反射方法 初始化类的子类对象 直接使用java.exe 调用某个类
- Linux环境下Oracle Sqlplus中使用上下键调用SQL语句的方法
- 使用扩展方法对调用进行验证
- 使用WCF扩展记录服务调用时间
- 在使用EF时调用DBFUNCTION扩展方法时,发生ENTITYCOMMANDEXECUTIONEXCEPTION 异常的解决办法
- 使用扩展方法对调用进行验证(转)
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
- 写一方法来实现两个变量的交换。在主调函数中定义两个整型变量,并初始化,调用交换方法,实现这两个变量的交换。(使用ref参数)
- Nginx环境使用CDN加速后网站日志获取真实用户IP地址方法
- jni使用c语言调用android shell命令方法
- C#错误:不能以方法的方式使用不可调用的
- 调用动态类型的扩展方法
- 使用Swift开发iOS项目、UI创建、方法调用
- Handler中post方法的调用流程和使用场景
- Struts2动态方法调用和使用通配符定义action