WCF后续之旅(16): 消息是如何分发到Endpoint的--消息筛选(Message Filter)
在介绍终结点的html#1320329" target=_blank>ListenUriMode时,我们提到了两个特殊的对象ChannelDispatcher和ChannelListener。这两个对象在整个WCF的消息分发系统中具有重要的地位,在这节里,我们对WCF的整个消息分发过程作一个简单的介绍。
一、连接请求的监听
当我们通过ServiceHost对某个服务进行寄宿的时候,实际上WCF是在为我们创建一个易做图,并监听来自外界的服务访问请求。我们举一个例子,比如针对服务CalculateService,具有如下的配置:该服务具有基于BasicHttpBinding的三个终结点,他们的地址(逻辑地址)分别为:http://127.0.0.1:9999/calculateservice,http://127.0.0.1:8888/calculateservice和http://127.0.0.1:7777/calculateservice,而前两个共享同一个ListenUri——http://127.0.0.1:6666/calculateservice。而第三个使用默认的ListenUri(也就是终结点地址)。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <services>
5: <service name="Artech.WcfServices.Services.CalculateService">
6: <endpoint address="http://127.0.0.1:9999/calculateservice" binding="basicHttpBinding"
7: contract="Artech.WcfServices.Contracts.ICalculate" listenUri="http://127.0.0.1:6666/calculateservice" />
8: <endpoint address="http://127.0.0.1:8888/calculateservice" binding="basicHttpBinding"
9: contract="Artech.WcfServices.Contracts.ICalculate" listenUri="http://127.0.0.1:6666/calculateservice" />
10: <endpoint address="http://127.0.0.1:7777/calculateservice" binding="basicHttpBinding"
11: contract="Artech.WcfServices.Contracts.ICalculate" />
12: </service>
13: </services>
14: </system.serviceModel>
15: </configuration>
16:
当我们通过ServiceHost对该服务进行寄宿的时候,会为该服务创建一个ServiceHost对象。当我们执行ServiceHost的Open方法的时候,WCF会创建两个ChannelDispatcher对象。为什么会是两个ChannelDispatcher对象呢?这是因为ChannelDispatcher是根据实际的监听地址创建的,在本例中,虽然我们为服务创建了三个终结点,由于前两个共享同一个监听地址,所所以针对于服务的ServiceHost对象,具有两个ChannelDispatcher对象与之匹配。对于每个ChannelDispatcher对象而言,他们各自对应一个唯一的ChannelListener对象,ChannelListener具有两个方面的作用,其一是绑定到一个具体的URI,监听来自外界的连接请求,其二就是当检测到请求后,创建信道堆栈(channel stack)接受、处理请求。ServiceHost的Open方法的执行,同时也预示着ChannelListener监听工作的开始。
由于我们为该服务注册了三个终结点,WCF还会创建3个EndpointDispatcher对象,分别于三个终结点对应。对于服务访问请求的消息,会先被对应的ChannelDispacher(这取决于该消息是从哪个ChannelListener接收到的)接收,ChannelDispacher本身并不会对该消息进行处理,而是为将它转发到对应的EndpointDispatcher上,基于该消息的所有后续处理都叫由EndpointDispatcher进行处理。对于这三个EndpointDispatcher对象,前面两个和第一个ChannelDispatcher匹配(根据实际的监听地址进行匹配)。
总结一下,一个CalculateService服务,对应着一个ServiceHost对象。该ServiceHost对象有具有两个ChannelDispatcher对象,这两个ChannelDispatcher各自具有一个ChannelListener对象,他们对应的监听地址分别为http://127.0.0.1:6666/calculateservice和http://127.0.0.1:7777/calculateservice。对于前一个ChannelDispatcher,具有两个与之匹配的EndpointDispatcher对象,后一个具有一个匹配的EndpointDispatcher对象。具体关系如下图所示:
我们可以通过一个例子在正式这一点,完全针对我们上面提供的配置,我们通过下面的代码将该服务在一个控制台应用中进行寄宿,然后打印出ChannelDispatcher和EndpointDispatcher的关系:
1: //---------------------------------------------------------------
2: // EndpointAddress & WCF Addressing (c) by 2008 Jiang Jin Nan
3: //---------------------------------------------------------------
4: using System.ServiceModel;
5: using Artech.WcfServices.Services;
6: using System.Threading;
7: using System;
8: using System.ServiceModel.Dispatcher;
9:
10: namespace Artech.WcfServices.Hosting
11: {
12: class Program
13: {
14: static void Main(string[] args)
15: {
16: using (ServiceHost serviceHost = new ServiceHost(typeof(CalculateService)))
17: {
18: serviceHost.Open();
19: int i=0;
20:
21: foreach (ChannelDispatcher channelDispatcher in serviceHost.ChannelDispatchers)
22: {
23: Console.WriteLine("ChannelDispatcher {0}: ListenUri: {1}", ++i, channelDispatcher.Listener.Uri);
24:  
补充:综合编程 , 其他综合 ,