- WCF技術剖析(卷1)
- 蔣金楠
- 1656字
- 2018-12-27 11:32:50
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); //... ... }
- Clojure Programming Cookbook
- Instant Node Package Manager
- 流量的秘密:Google Analytics網站分析與優化技巧(第2版)
- JavaScript修煉之道
- ASP.NET Core 2 and Vue.js
- 從0到1:HTML+CSS快速上手
- Python進階編程:編寫更高效、優雅的Python代碼
- Building a Recommendation Engine with Scala
- Java Web應用開發技術與案例教程(第2版)
- 用戶體驗增長:數字化·智能化·綠色化
- C語言程序設計同步訓練與上機指導(第三版)
- iOS自動化測試實戰:基于Appium、Python與Pytest
- ASP.NET程序開發范例寶典
- 持續集成與持續交付實戰:用Jenkins、Travis CI和CircleCI構建和發布大規模高質量軟件
- 軟件測試綜合技術