扩展WCF自定义行为(二)
在上一篇文章中介绍了WCF运行时体系结构及客户、服务器端的扩展点。下面以一个简单的Demo来演示扩展WCF的运行时行为。源代码下载。
假设有一个WCF服务接口,提供以用户名进行用户身份编号的查询。
public interface IIdentityService
{
[IdentityValidate]
[IdentityCache]
[OperationContract]
int GetIDByName(string name);
}
一,自定义参数检查器
假设业务规则要求IIdentityService服务接口的用户名参数不能为空,且必须不少于3个字符。在这种情况下,我们需要在服务器端进行参数检查,此检查在服务接口操作(GetIDByName)调用前执行,如果参数检查不通过,抛出异常,终止执行后续的操作调用。自定义参数检查器都实现IParameterInspector接口。该接口定义两个方法:AfterCall、BeforeCall,分别是在服务接口操作调用前和调用后进行参数检查。
{
int identityParamIndex;
public NameInspector() : this(0) { }
public NameInspector(int ParamIndex)
{
this.identityParamIndex = ParamIndex;
}
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
public object BeforeCall(string operationName, object[] inputs)
{
string Param = inputs[this.identityParamIndex] as string;
if (Param==null||Param .Length <3)
throw new FaultException("Invalid name. ");
return null;
}
#endregion
}
同时,可以定义一个申明标签来添加这个自定义参数检查器到WCF的运行时行为中。该标签实现IOperationBehavior接口。
{
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription,
ClientOperation clientOperation)
{
NameInspector nameInspector = new NameInspector();
clientOperation.ParameterInspectors.Add(nameInspector);
}
public void ApplyDispatchBehavior(OperationDescription operationDescription,
DispatchOperation dispatchOperation)
{
NameInspector nameInspector = new NameInspector();
dispatchOperation.ParameterInspectors.Add(nameInspector);
}
public void Validate(OperationDescription operationDescription)
{
}
#endregion
}
二, 自定操作调用器
假设IIdentityService服务接口需要频繁地被调用、而且每次调用的服务端资源开销比较大。在这种情况下我们希望在服务端操作调用中缓存服务调用的结果。自定义一个服务端操作调用器,该操作调用器实现IOperationInvoker接口,并在Invoke方法中使用了调用结果缓存功能。Invoke方法首先尝试在其缓存中查询参数对应的结果,如果找到则直接返回该结果,如果找不到缓存结果则调用默认的操作调用器获取结果并缓存该结果。
{
IOperationInvoker innerOperationInvoker;
Dictionary<string, int> identityCache = new Dictionary<string, int>();
public IdentityCaching(IOperationInvoker innerOperationInvoker)
{
this.innerOperationInvoker = innerOperationInvoker;
}
#region IOperationInvoker Members
public object[] AllocateInputs()
{
return this.innerOperationInvoker.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
string name = inputs[0] as string;
int value;
if (this.identityCache.TryGetValue(name, out value))
{
outputs = new object[0];
return value;
}
else
{
value = (int)this.innerOperationInvoker.Invoke(
instance, inputs, out outputs);
identityCache[name] = value;
return value;
}
}
public IAsyncResult InvokeBegin(object instance, object[] inputs,
AsyncCallback callback, object state)
{
return this.innerOperationInvoker.InvokeBegin(
instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return this.innerOperationInvoker.InvokeEnd(
instance, out outputs, result);
}
public bool IsSynchronous
{
get { return innerOperationInvoker.IsSynchronous; }
}
#endregion
}
同时,可以定义一个申明标签来添加这个自定操作调用器到WCF的运行时行为中。该标签实现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)
{
dispatchOperation.Invoker = new IdentityCaching(dispatchOperation.Invoker);
}
public void Validate(OperationDescription operationDescription)
{
}
#endregion
}
总结
WCF的体系结构运行进行大量的运行时自定义,其分布在调度、代理相交互的整个生命周期。除了执行参数检查、消息检查、消息格式化、操作选择、操作调用等自定义扩展外,还可以定义更高级的扩展来处理实例化、并发、寻址和安全等事项。这些更高级的扩展将在以后的文章中介绍。
代码下载