您的位置:首页 > 其它

真实世界:使用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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐