官术网_书友最值得收藏!

2.3.4 消息篩選

在上面的案例演示中,提到了兩個特殊的對象ChannelDispatcher和ChannelListener。這兩個對象在整個WCF的消息分發系統中具有重要的地位,在這節里,我們對WCF的整個消息分發過程作一個簡單的介紹。

連接請求的監聽

當服務被成功寄宿時,WCF在服務端創建一個或多個監聽器,用于服務調用請求的監聽。舉個例子,我們為服務CalculatorService添加三個基于BasicHttpBinding的終結點,它們分別具有如下3個終結點地址(邏輯地址)。

http://127.0.0.1:9999/CalculatorService

http://127.0.0.1:8888/CalculatorService

http://127.0.0.1:7777/CalculatorService

我們為前兩個終結點指定一個不同于終結點地址的監聽地址(物理地址):http://127.0.0.1:6666/CalculatorService。第三個終結點的監聽地址(物理地址)與終結點地址(邏輯地址)共享相同的URI:http://127.0.0.1:7777/CalculatorService。相應的配置如下:

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
            <system.serviceModel>
                <services>
                    <service name="Artech.WcfServices.Services.CalculatorService">
                        <endpoint address="http://127.0.0.1:9999/CalculatorService"
                          binding="basicHttpBinding"
                            contract="Artech.WcfServices.Contracts.ICalculator"
                              listenUri="http://127.0.0.1:6666/CalculatorService" />
                        <endpoint address="http://127.0.0.1:8888/CalculatorService"
                            binding="basicHttpBinding"
                            contract="Artech.WcfServices.Contracts.ICalculator"
                              listenUri="http://127.0.0.1:6666/CalculatorService" />
                        <endpoint address="http://127.0.0.1:7777/CalculatorService"
                          binding="basicHttpBinding"
                            contract="Artech.WcfServices.Contracts.ICalculator" />
                    </service>
                </services>
            </system.serviceModel>
        </configuration>

現在的情況是,1個服務、3個終結點、2個監聽地址。當服務被成功寄宿時,WCF會創建兩個信道分發器(ChannelDispatcher)對象,每個信道分發器各擁有屬于自己的信道監聽器(ChannelListener),它們分別綁定到兩個監聽地址對應的端口進行服務調用請求的監聽。此外,WCF還會為服務的3個終結點創建3個終結點分發器(EndpointDispatcher),當信道分發器通過信道監聽器接收到消息時,將會根據消息自身攜帶的信息選擇與之相匹配的終結點分發器,根據消息進行終結點分發器的選擇機制稱為消息篩選(Message Filter)。關于上面介紹的場景,圖2-9體現了基于CalculatorService對應的ServiceHost、ChannelDispatcher和EndpointDispatcher之間的關系。

圖2-9 ServiceHost-ChannelDispatcher-EndpointDispatcher

圖2-9揭示的圍繞CalculatorService的各個相關對象之間的關系也可以從下面的程序得以印證。

        using System.ServiceModel;
        using Artech.WcfServices.Services;
        using System.Threading;
        using System;
        using System.ServiceModel.Dispatcher;
        namespace Artech.WcfServices.Hosting
        {
            class Program
            {
                static void Main(string[] args)
                {
                    using (ServiceHost serviceHost = new ServiceHost
                      (typeof(CalculatorService)))
                    {
                        serviceHost.Open();
                        int i=0;
                        foreach (ChannelDispatcher channelDispatcher in serviceHost.
                          ChannelDispatchers)
                        {
                            Console.WriteLine("ChannelDispatcher {0}: ListenUri: {1}",
                              ++i, channelDispatcher.Listener.Uri);
                            int j = 0;
                            foreach (EndpointDispatcher endpointDispatcher in
                              channelDispatcher.Endpoints)
                            {
                                    Console.WriteLine("\tEndpointDispatcher {0}:
                                      EndpointAddress: {1}", ++j,endpointDispatcher.
                                      EndpointAddress.Uri);
                            }
                        }
                        Console.Read();
                    }
                }
            }
            }

輸出結果:

        ChannelDispatcher 1: ListenUri: http://127.0.0.1:6666/CalculatorService
            EndpointDispatcher 1: EndpointAddress: http://127.0.0.1:9999/
              CalculatorService
            EndpointDispatcher 2: EndpointAddress: http://127.0.0.1:8888/
              CalculatorService
        ChannelDispatcher 2: ListenUri: http://127.0.0.1:7777/CalculatorService
            EndpointDispatcher 1: EndpointAddress: http://127.0.0.1:7777/
              CalculatorService

EndpointDispatcher的選擇和消息的分發

在WCF整個消息監聽與分發體系中,信道分發器和終結點分發器是兩個核心的對象。信道分發器進行請求監聽和消息接收,終結點分發器最終完成對消息的處理。信道分發器接收的消息最終需要分發給相應的終結點分發器,而消息篩選解決了對終結點的選擇問題。消息篩選依賴于終結點分發器兩個重要的對象:AddressFilter和Contractfilter,它們分別實現基于終結點地址和服務契約的消息篩選。

        public class EndpointDispatcher
        {
            //其他成員
            public MessageFilter AddressFilter  { get; set; }
            public MessageFilter ContractFilter { get; set; }
        }

AddressFilter和Contractfilter具有相同的類型:System.ServiceModel.Dispatcher. MessageFilter。MessageFilter是一個抽象類型,定義了兩個重載的Match方法,用以判斷持有該MessageFilter的EndpointDispatcher是否和接收的消息相匹配。

        public abstract class MessageFilter
        {
            public abstract bool Match(Message message);
            public abstract bool Match(MessageBuffer buffer);
        }

當ChannelDispatcher接收到請求消息時,會遍歷屬于自己的EndpointDispatcher列表,獲取它們的兩個MessageFilter:AddressFilter和Contractfilter,并將消息對象傳入Match方法。如果返回值均為true,則意味著相應的EndpointDispatcher為真正的目標終結點。

WCF定義了以下6種不同的MessageFilter類型,它們均直接繼承自MessageFilter抽象類型。

ActionMessageFilter:每一個服務操作具有一個Action屬性,通過OperationContractAttribute特性進行定義。一個服務契約包含一個或多個服務操作,所以一個終結點具有一組Action列表。AddressMessageFilter通過判斷SOAP消息的Action報頭的值是否在終結點Action列表之中,從而選擇正確的終結點;

EndpointAddressMessageFilter:EndpointAddress是一個終結點不可或缺的元素,EndpointAddress不僅包含服務的地址,也包含尋址的報頭(AddressHeader),能夠通過EndpointAddressMessageFilter篩選的終結點需要同時滿足兩個要求:終結點地址URI要與SOAP的To報頭值一致;SOAP消息具一致的報頭信息;

XPathMessageFilter:SOAP消息也是一個XML,所以可以根據一個具體的XPath表達式和SOAP的內容進行匹配;

PrefixEndpointAddressMessageFilter:和EndpointAddressMessageFilter篩選機制類似,不同的是PrefixEndpointAddressMessageFilter采用“最長前綴匹配”機制。比如,終結點地址指定的URI為http://www.artech.com/Foo,而請求消息的To報頭的URI為http://www.artech.com/Foo/Bar,這樣可以被認為是匹配的;

MatchAllMessageFilter:不管消息的內容是什么,都會匹配成功;

MatchNoneMessageFilter:和MatchAllMessageFilter相反,不管消息的內容是什么,都不會匹配成功。

在默認情況下,EndpointDispatcher的AddressFilter和ContractFilter分別采用EndpointAddressMessageFilter和ActionMessageFilter。如果希望使用其他的值,可以通過自定義Behavior的形式覆蓋默認的值。對于AddressFilter,最直接的方式就是通過ServiceBehaviorAttribute的AddressFilterMode屬性指定你所需要的MessageFilter模式。

        public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
        {
            //其他成員
            public AddressFilterMode AddressFilterMode { get; set; }
        }
        public enum AddressFilterMode
        {
            Exact,
            Prefix,
            Any
        }

AddressFilterMode中的3個枚舉值(Exact、Prefix和Any)對應的MessageFilter分別為:EndpointAddressMessageFilter、PrefixEndpointAddressMessageFilter和MatchAllMessageFilter。下面的代碼將AddressFilter指定為MatchAllMessageFilter。

        [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
        public class CalculatorService:ICalculator
        {
            //省略成員
        }
主站蜘蛛池模板: 二连浩特市| 广饶县| 肇东市| 黔西县| 江安县| 商水县| 济宁市| 贡山| 古丈县| 长子县| 常州市| 晋宁县| 五常市| 广水市| 五大连池市| 民丰县| 屯留县| 南丹县| 肃宁县| 常宁市| 鲁甸县| 英超| 凉城县| 阿巴嘎旗| 杭锦后旗| 贺兰县| 安溪县| 固镇县| 仁怀市| 浪卡子县| 东丰县| 宿迁市| 肇州县| 永新县| 祁门县| 阿拉尔市| 华池县| 平南县| 惠来县| 松潘县| 英德市|