WCF技术剖析(卷1)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.2.1 服务寄宿对绑定的指定

当我们通过一个托管的应用程序对一个服务进行自我寄宿的时候,一般会为服务创建一个ServiceHost对象,然后通过ServiceHost的AddServiceEndpoint方法为之添一个或多个终结点。ServiceHost和基类ServiceHostBase定义一个了若干重载的AddServiceEndpoint方法,每个方法都包含一个Binding对象。下面的代码片断列出了所有定义在ServiceHost和ServiceHostBase中的AddServiceEndpoint方法。

        public abstract class ServiceHostBase
        {
            //其他成员
            public ServiceEndpoint AddServiceEndpoint(string implementedContract,
              Binding binding, string address);
            public ServiceEndpoint AddServiceEndpoint(string implementedContract,
              Binding binding, Uri address);
            public ServiceEndpoint AddServiceEndpoint(string implementedContract,
              Binding binding, string address, Uri listenUri);
            public ServiceEndpoint AddServiceEndpoint(string implementedContract,
              Binding binding, Uri address, Uri listenUri);
        }
        public abstract class ServiceHost
        {
            //其他成员
            public ServiceEndpoint AddServiceEndpoint(Type implementedContract,
              Binding binding, string address);
            public ServiceEndpoint AddServiceEndpoint(Type implementedContract,
              Binding binding, Uri address);
            public ServiceEndpoint AddServiceEndpoint(Type implementedContract,
              Binding binding, string address, Uri listenUri);
            public ServiceEndpoint AddServiceEndpoint(Type implementedContract,
              Binding binding, Uri address, Uri listenUri);
        }

在下面的代码中,为CalculatorService服务添加了3个终结点,这3个终结点对应的绑定类型分别为:BasicHttpBinding、WsHttpBinding和NetTcpBinding。

        namespace Artech.WcfServices.Hosting
        {
            class Program
            {
                static void Main(string[] args)
                {
                      using (ServiceHost serviceHost = new ServiceHost
                        (typeof(CalculatorService)))
                      {
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), new
                            BasicHttpBinding(), "http://127.0.0.1:6666/
                            CalculatorService");
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), new
                            WSHttpBinding(), "http://127.0.0.1:7777/
                            CalculatorService");
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), new
                            NetTcpBinding(),"net.tcp://127.0.0.1:8888/
                            CalculatorService");
                          serviceHost.Open();
                          Console.Read();
                      }
                }
            }
        }

任何一种绑定类型对应着一种确定的传输方式,比如BasicHttpBinding和WsHttpBinding采用HTTP传输协议;NetTcpBinding采用TCP;NetMsmqBinding采用MSMQ的传输方式。当我们创建终结点的时候,绑定对象和指定的地址必须相互匹配,否则将会抛出异常。比如在下面的代码中,为一个基于BasicHttpBinding的终结点指定了一个NET.TCP地址,当ServiceHost的Open方法被执行的时候将会抛出一个如图3-7的ArgumentExcetion异常。

图3-7 URI与绑定不匹配时的异常

        using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
        {
            serviceHost.AddServiceEndpoint(typeof(ICalculator), new
              BasicHttpBinding(), "net.tcp://127.0.0.1:8888/CalculatorService");
            serviceHost.Open();
            //其他操作
        }

当我们采用基地址/相对地址的方式对服务进行寄宿的时候,对于终结点中指定的相对地址,WCF会在对应的ServiceHost基地址列表中寻找传输协议和与绑定类型相匹配的基地址,两者相互组合构成完整的终结点地址。比如,在下面的代码中,为服务CalculatorService添加了两个基地址:http://127.0.0.1:8888和net.tcp://127.0.0.1:9999。并通过AddServiceEndpoint方法添加了两个终结点,这不同的终结点具有不同的绑定类型(WsHttpBinding和NetTcpBinding)和相同的相对地址(CalculatorService)。WCF会根据绑定的具体类型,在基地址列表中寻找与传输协议匹配的基地址,基地址和相对地址相互组合,构成最终的终结点地址。在此例中,WsHttpBinding对应的终结点地址为http://127.0.0.1:888/CalculatorService,NetTcpBinding对应的终结点地址为net.tcp://127.0.0.1:9999/CalculatorService。

        namespace Artech.WcfServices.Hosting
        {
            class Program
            {
                static void Main(string[] args)
                {
                      Uri[] baseAddresses = new Uri[] { new Uri("http://127.0.0.1:8888"),
                        new Uri("net.tcp://127.0.0.1:9999") };
                      using (ServiceHost serviceHost = new
                        ServiceHost(typeof(CalculatorService), baseAddresses))
                      {
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), new
                            WSHttpBinding(), "CalculatorService");
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), new
                            NetTcpBinding(), "CalculatorService");
                          serviceHost.Open();
                          Console.Read();
                      }
                }
            }
        }

当进行服务寄宿的时候,在执行ServiceHost的Open方法之前,可以为绑定对象进行相应的定制,设置相关的属性。在下面的代码片断中,为服务添加终结点之前,先创建了一个BasicHttpBinding对象,并设置了该对象相应的属性(AllowCookie、HostNameComparisonMode和MaxBufferPoolSize)。

        namespace Artech.WcfServices.Hosting
        {
            class Program
            {
                static void Main(string[] args)
                {
                      using (ServiceHost serviceHost = new ServiceHost
                        (typeof(CalculatorService)))
                      {
                          BasicHttpBinding binding = new BasicHttpBinding();
                          binding.AllowCookies = true;
                          binding.HostNameComparisonMode = HostNameComparisonMode.Exact;
                          binding.MaxBufferPoolSize = 3721;
                          serviceHost.AddServiceEndpoint(typeof(ICalculator), binding,
                            "http://127.0.0.1:8888/CalculatorService");
                          serviceHost.Open();
                          Console.Read();
                      }
                }
            }
        }

终结点的绑定也可以通过配置的方式进行指定,绑定的类型可以直接通过终结点配置节的binding属性进行配置,比如通过下面的配置,为CalculatorService添加了3个终结点,它们分别采用了3种不同类型的绑定:BasicHttpBinding、WsHttpBinding和NetTcpBinding。

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

所有的绑定对象都具有一些共同的属性,比如OpenTimeout、CloseTimeout、SendTimeout、ReceiveTimeout等。此外,不同的绑定对象也有一些专属于自己的属性。如果没有显式地对这些属性进行设置,那么将采用这些属性的默认值。如果希望通过配置的方式对绑定对象进行定制,须要将相关设置定义在binding列表中。下面的配置中,在<bindings>/<basicHttpBinding>中添加了一个BasicHttpBinding,并为其指定了一系列的属性,并将该BasicHttpBinding命名为“MyBinding”,在具体的终结点中,通过bindingConfiguration根据名称对绑定进行引用。

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
            <system.serviceModel>
                <bindings>
                      <basicHttpBinding>
                        <binding name="MyBinding" openTimeout="00:05:00"
                          receiveTimeout="00:15:00" sendTimeout="00:15:00"
                          allowCookies="true" />
                      </basicHttpBinding>
                </bindings>
                <services>
                      <service name="Artech.WcfServices.Services.CalculatorService">
                        <endpoint address="http://127.0.0.1:6666/CalculatorService"
                          binding="basicHttpBinding" bindingConfiguration="MyBinding"
                          contract="Artech.WcfServices.Contracts.ICalculator" />
                      </service>
                </services>
            </system.serviceModel>
        </configuration>