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

3.2.2 服務調用對綁定的指定

通過前面章節的介紹,我們知道了WCF服務調用具有兩種典型的方式:一種是借助代碼生成工具(比如SvcUtil.exe)導入元數據生成客戶端代碼和配置,添加服務引用采用的便是這種方式。代碼生成工具最終會創建一個繼承自ClientBase<TChannel>的服務代理類型。另一種則是通過ChannelFactory直接創建服務代理對象進行服務調用。

為ClientBase<TChannel>指定綁定

無論是直接借助于SvcUtil.exe,還是添加服務引用的方式,生成的核心類是繼承自System.ServiceModel.ClientBase<TChannel>的子類,TChannel為服務契約類型。

        namespace Artech.WcfServices.Contracts
        {
            [ServiceContract(NameSpace="http://www.artech.com/")]
            public interface ICalculator
            {
                [OperationContract]
                double Add(double x, double y);
            }
        }

針對上面一個服務契約,將會生成3個類型:ICalculator、ICalculatorChannel、CalculateClient。ICalculator可以看成是客戶端的等效服務契約(Equavilent ServiceContract);ICalculatorChannel繼承了System.ServiceModel.IClientChannel,IClientChannel定義了客戶端信道的基本行為;CalculateClient是最終用于服務訪問的服務代理類,該類繼承了泛型基類ClientBase<ICalculator>,并實現了服務契約。CalculateClient的定義如下。

        namespace Artech.WcfServices.Clients.ServiceReference {
            //其他類型
            public partial class CalculateClient : System.ServiceModel.
              ClientBase<Artech.WcfServices.Clients.ServiceReference.ICalculator>,
              Artech.WcfServices.Clients.ServiceReference.ICalculator {
                public CalculateClient() {
                }
                public CalculateClient(string endpointConfigurationName) :
                        base(endpointConfigurationName) {
                }
                public CalculateClient(string endpointConfigurationName, string
                  remoteAddress) :
                        base(endpointConfigurationName, remoteAddress) {
                }
                public CalculateClient(string endpointConfigurationName,
                  System.ServiceModel.EndpointAddress remoteAddress) :
                        base(endpointConfigurationName, remoteAddress) {
                }
                public CalculateClient(System.ServiceModel.Channels.Binding binding,
                  System.ServiceModel.EndpointAddress remoteAddress) :
                        base(binding, remoteAddress) {
                }
                public double Add(double x, double y) {
                      return base.Channel.Add(x, y);
                }
            }
        }

在生成的CalculateClient類中定義了5個構造函數重載,它們都是通過調用基類相應的構造函數實現的。綁定對象可以通過其中一個構造函數指定:

        public CalculateClient(System.ServiceModel.Channels.Binding binding,
          System.ServiceModel.EndpointAddress remoteAddress) :
              base(binding, remoteAddress) {
        }

下面的代碼片斷簡單演示了通過創建CalculateClient實現對CalculatorService的調用,在構造該對象的時候顯式指定綁定對象和終結點地址:

        namespace Artech.WcfServices.Clients
        {
            class Program
            {
                static void Main(string[] args)
                {
                      EndpointAddress address = new EndpointAddress
                        ("http://127.0.0.1:6666/CalculatorService");
                      Binding binding = new BasicHttpBinding();
                      double result;
                      using (CalculateClient calculator = new CalculateClient(binding,
                        address))
                      {
                          result = calculator.Add(1, 2);
            //其他操作
                      }
                }
            }
        }

對于生成的服務代理類的5個重載構造函數,只有唯一一個能夠顯式地指定綁定對象,如果使用其他的構造函數來創建服務代理對象,使用的是通過配置方式指定的綁定。服務代理類通過endpointConfigurationName引用定義配置文件中的某個終結點,并采用該終結點的綁定。在客戶端的配置較服務端更加簡潔,所有的終結點列表位于<client>配置節中,在具體的<endpoint>配置中通過binding屬性指定綁定類型。

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
            <system.serviceModel>
                <client>
                    <endpoint name="CalculatorService_wsHttpBinding" address=
                      "http://127.0.0.1:8888/CalculatorService" binding=
                      "wsHttpBinding" bindingConfiguration="" contract="Artech.
                        WcfServices.Contracts.ICalculator">
                    </endpoint>
                    <endpoint name="CalculatorService_netTcpBinding" address=
                      "net.tcp://127.0.0.1:9999/CalculatorService" binding=
                      "netTcpBinding" bindingConfiguration="" contract="Artech.
                        WcfServices.Contracts.ICalculator">
                    </endpoint>
                </client>
            </system.serviceModel>
        </configuration>

和服務端一樣,依然可以通過配置的方式定義需要的綁定。所有定制的綁定位于<bindings>配置節中。如下面的配置所示,名稱為calculateservice的終結點采用了定制的BasichHttpBinding,我們修改了BasicHttpBinding默認的Timeout時間。

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
            <system.serviceModel>
                <bindings>
                      <basicHttpBinding>
                          <binding name="BasicHttpBinding_ICalculator" closeTimeout=
                            "00:01:00" openTimeout="00:02:00" receiveTimeout="00:05:00"
                            sendTimeout="00:02:00" />
                      </basicHttpBinding>
                </bindings>
                <client>
                      <endpoint address="http://127.0.0.1:9999/CalculatorService"
                        binding="basicHttpBinding" bindingConfiguration=
                        "BasicHttpBinding_ICalculator" contract="Artech.WcfServices.
                        Contracts.ICalculator" name="CalculatorService" />
                </client>
            </system.serviceModel>
        </configuration>

如果服務調用的終結點完全通過配置進行設置的話,客戶端代碼就可以進一步得到簡化。在下面的客戶端代碼中,當創建CalculateClient對象時,直接指定終結點配置名稱就可以了。

        using System.ServiceModel;
        using System.ServiceModel.Channels;
        namespace Artech.WcfServices.Clients
        {
            class Program
            {
                static void Main(string[] args)
                {
                      double result;
                      using (CalculateClient calculator = new CalculateClient
                        ("CalculatorService"))
                      {
                          result = calculator.Add(1, 2);
            ......
                      }
                }
            }
        }

為ChannelFactory<TChannel>指定綁定

從遠程調用的角度來理解WCF的客戶端程序,其目的在于創建一個代理對象實現遠程調用;從消息交換的角度來講,WCF客戶端程序的目的在于創建一個信道棧用于向服務端發送消息和接收回復。所以我們需要的就是通過一個對象來創建這樣的服務代理或是信道棧,從編程模型的角度來看,這個對象就是System.ServiceModel.ChannelFactory <TChannel>。實際上,System.ServiceModel.ClientBase<TChannel>在內部也是通過ChannelFactory<TChannel>來創建這個TChannel的。

通過ChannelFactory<TChannel>,可以自由地指定終結點的三要素(地址、綁定和契約,其中泛型類型即代表契約類型)。下面是ChannelFactory<TChannel>的主要方法定義。

        public class ChannelFactory<TChannel> : ChannelFactory,
        IChannelFactory<TChannel>, IChannelFactory, ICommunicationObject
        {
            public ChannelFactory();
            public ChannelFactory(Binding binding);
            public ChannelFactory(ServiceEndpoint endpoint);
            public ChannelFactory(string endpointConfigurationName);
            public ChannelFactory(Binding binding, EndpointAddress remoteAddress);
            public ChannelFactory(Binding binding, string remoteAddress);
            public ChannelFactory(string endpointConfigurationName, EndpointAddress
              remoteAddress);
            public TChannel CreateChannel();
            public TChannel CreateChannel(EndpointAddress address);
            public virtual TChannel CreateChannel(EndpointAddress address, Uri via);
            //其他成員
        }

由于ChannelFactory<TChannel>的目的是通過一個終結點對象創建用于服務調用的代理,所以定義一系列的構造函數顯式地指定一個確定終結點對象或是構成終結點的兩個要素,地址和綁定(另一個要素已經通過泛型類型確定下來)。在沒有顯式指定地址或綁定的情況下,通過endpointConfigurationName參數引用定義在配置文件中的終結點,采用配置的地址或綁定。當ChannelFactory<TChannel>被成功創建時,就可以通過它來創建實現了服務企業約定的服務代理對象,并由它進行服務的調用。下面的代碼中 ,借助ChannelFactory<TChannel>,完全使用代碼的方式實現了服務的調用。

        namespace Artech.WcfServices.Clients
        {
            class Program
            {
                static void Main(string[] args)
                {
                      double result;
                      EndpointAddress  address = new EndpointAddress
                        ("http://127.0.0.1:9999/CalculatorService");
                      Binding binding = new BasicHttpBinding();
                      ContractDescription contract = ContractDescription. GetContract
                        (typeof(ICalculator));
                      ServiceEndpoint endpoint = new ServiceEndpoint(contract,
                        binding,address);
                      using (ChannelFactory<ICalculator> channelFactory = new
                        ChannelFactory<ICalculator>(endpoint))
                      {
                          ICalculator calculator = channelFactory.CreateChannel();
                          using (calculator as IDisposable)
                          {
                              result = calculator.Add(1, 2);
                      ......
                          }
                      }
                }
            }
        }

如果采用配置文件中配置的終結點信息,將會使代碼得到極大的簡化。如果使用下面的配置,上面那么一大段代碼就會得到極大的簡化,在創建ChannelFactory<TChannel>時只須要指定終結點配置名稱(CalculatorService)就可以了。

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>
            <system.serviceModel>
                <client>
                      <endpoint address="http://127.0.0.1:9999/CalculatorService"
                        binding="basicHttpBinding" contract="Artech.WcfServices.
                        Contracts.ICalculator" name="CalculatorService" />
                </client>
            </system.serviceModel>
        </configuration>
        namespace Artech.WcfServices.Clients
        {
            class Program
            {
                static void Main(string[] args)
                {
                      double result;
                      using (ChannelFactory<ICalculator> channelFactory = new
                        ChannelFactory<ICalculator>(“CalculatorService”))
                      {
                          ICalculator calculator = channelFactory.CreateChannel();
                          using (calculator as IDisposable)
                          {
                              result = calculator.Add(1, 2);
                              //......
                        }
                      }
                }
            }
        }

ChannelFactory<TChannel>類型除了提供實例方法CreateChannel之外,還提供一個靜態的同名方法,借助于該靜態方法,你無須再創建ChannelFactory<TChannel>對象就可以即席創建服務代理對象。

        public class ChannelFactory<TChannel> : ChannelFactory,
          IChannelFactory<TChannel>, IChannelFactory, ICommunicationObject
        {
            public static TChannel CreateChannel(Binding binding, EndpointAddress
              endpointAddress, Uri via);
            //... ...
        }
主站蜘蛛池模板: 平顶山市| 南京市| 安阳市| 宁明县| 梁山县| 呼图壁县| 得荣县| 商南县| 高邮市| 鹤峰县| 云龙县| 柳河县| 蚌埠市| 米易县| 名山县| 武乡县| 东乡县| 剑阁县| 若尔盖县| 河南省| 焦作市| 新余市| 鄂托克前旗| 中方县| 邹平县| 扎兰屯市| 洪洞县| 昌平区| 乌鲁木齐县| 荣成市| 玉龙| 新乡县| 丁青县| 北海市| 普兰店市| 石景山区| 高州市| 武宁县| 张掖市| 长岛县| 萨迦县|