这一篇中,我将和大家探讨一下如何扩展WCF service端的Dispatcher。因为可以讨论的方面是十分多的,所以在这里我只是列举了几个可能是比较常用的扩展点。至于关于Dispatcher其他的扩展,相信大家不难找出。
首先我们看一下Dispatcher的结构:

图是从MSDN上搞到的,有点大。
我们可以看到在ServiceHost下有两个Dispatcher:ChannelDispatcher、EndpointDispatcher。每个EndpointDispatcher中都有DispatchRuntime和DispatchOperation。DispatchRuntime将Message分发到对应的DispatchOperation,由后者来调用对应的方法来完成整个操作。接下来的实例中我们就从这两个类着手来进行扩展。不过首先我们要知道,这两个类处的层级是不同的。DispatchRuntime允许我们在Contract的范围内进行拦截和扩展,而DispatchOperation允许我们在Opertaion的范围内进行拦截和扩展。可能现在有点不清楚,待会看实例就会很明白了,其实对于我们来说就是获得的信息不一样而已。
首先我们先建一个WCF的应用程序,至于怎么建立我就不说了,这个也不是本文的主题。
接下来就干正事了。我们要清楚,扩展的方式就是将我们客制化的东西加入到WCF的运行时中。怎么加呢?对了,首先想到的应该就是Behavior。WCF中有各种各样的Behavior:Service Behavior、Endpoint Behavior、Operation Behavior等。至于你想选择什么Behavior,就根据你想把这扩展作用的范围来选择好了。这里我选择用Service Behavior。所以需要添加一个类来实现IServiceBehavior接口。
public class MyBehavior : Attribute, IServiceBehavior

{

public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

{
}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)

{
foreach (ChannelDispatcher ch1 in serviceHostBase.ChannelDispatchers)

{
foreach (EndpointDispatcher end in ch1.Endpoints)

{
}
}
}

public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)

{
}
}
在ApplyDispathBehavior方法中,通过两个循环我们就获得了EndpointDispatcher对象了,接下来就可以用它来访问到DispatchRuntime和DispatchOperation了。
现在要插入讲一下我的例子中待会要用到的两个接口:
IDispatchMessageInspector和
IParameterInspector。
IDispatchMessageInspector根据名字就可以看出主要用来拦截服务器端的消息的,定义如下:
public interface IDispatchMessageInspector


{
// Methods
object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext);
void BeforeSendReply(ref Message reply, object correlationState);
}


IParameterInspector主要用来在方法调用时拦截参数的,定义如下:
public interface IParameterInspector


{
// Methods
void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState);
object BeforeCall(string operationName, object[] inputs);
}


所以接下来我们就用这两个接口来分别实现在DispatchRuntime和DispatchOperation上的拦截,下面新加入两个类分别实现这两个接口:
public class MyParameterInspector : IParameterInspector

{

public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)

{
}

public object BeforeCall(string operationName, object[] inputs)

{
Console.WriteLine(operationName + ": ");
foreach (object var in inputs)

{
Console.WriteLine("input: " + var.ToString());
}
return null;
}
}

public class MyMessageInspector : IDispatchMessageInspector

{

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)

{
Trace.WriteLine(request);
return null;
}

public void BeforeSendReply(ref Message reply, object correlationState)

{
Trace.WriteLine(reply);
}
}
然后把他们加入到Dispatch中,修改ApplyDispathBehavior方法:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)


{
foreach (ChannelDispatcher ch1 in serviceHostBase.ChannelDispatchers)

{
foreach (EndpointDispatcher end in ch1.Endpoints)

{
end.DispatchRuntime.MessageInspectors.Add(new MyMessageInspector());
foreach (DispatchOperation op in end.DispatchRuntime.Operations)

{
op.ParameterInspectors.Add(new MyParameterInspector());
}
}
}
}
最后,在你的Service类上打上标签就可以了:[MyBehavior]。
编译以后运行一下看看效果吧。

本文的例子并没有什么实质的使用场景,至于扩展Dispatcher可以对你的应用程序带来多大的好处,还希望你继续深入研究。当然,可扩展的点也不仅仅是MessageInspectors和ParameterInspectors。