[WCF 4.0新特性] 默认终结点
很多WCF的初學者是從之前的Web服務上轉移過來的,他們非常懷念.asmx Web服務無配置的服務寄宿方式。你只需要在定義Web服務的時候再表示服務操作的方法上應用WebMethodAttribute特性就可以了,完全可以不需要手工進行相應的配置,因為Web服務運行時會自動為你添加默認的配置。但是對于WCF來說,在進行服務寄宿的時候,你必須以編程或者配置的方式為服務添加至少一個終結點,而終結點需要具備基本的ABC三要素。
對于最新版本的WCF編程人員來說,你也可以采用無配置的服務寄宿了,這主要得益于WCF提供的默認終結點機制。所謂默認終結點,顧名思義,就是在你尚未為寄宿的服務添加任何終結點的時候,WCF會自動根據服務的基地址(Base Address)為你創建一個或者多個默認的終結點。
我們舉個簡單的例子,現在我們具有一個服務叫做GreetingService的服務,它實現了兩個服務契約IHello和IGoodbye。下面的代碼片斷提供了服務類型GreetingService和服務契約接口的定義。
1: [ServiceContract] 2: public interface IHello 3: { 4: [OperationContract] 5: void SayHello(string name); 6: } 7: [ServiceContract] 8: public interface IGoodbye 9: { 10: [OperationContract] 11: void SayGoodbye(string name); 12: } 13: public class GreetingService : IHello, IGoodbye 14: { 15: public void SayHello(string name) 16: { 17: //省略實現 18: } 19: public void SayGoodbye(string name) 20: { 21: //省略實現 22: } 23: }現在我們創建一個簡單的控制臺程序作為服務的宿主,在不提供任何配置文件的情況下調用如下的代碼對服務進行自我寄宿。當用于寄宿服務的ServiceHost被開啟之后,打印出其具有的終結點信息。
1: Uri baseHttpAddress = new Uri("http://127.0.0.1/greetingservice "); 2: Uri baseTcpAddress = new Uri("net.tcp://127.0.0.1/greetingservice "); 3: ServiceHost host = new ServiceHost(typeof(GreetingService), baseHttpAddress, baseTcpAddress); 4: host.Open(); 5: int index = 0; 6: foreach (ServiceEndpoint endpoint in host.Description.Endpoints) 7: { 8: Console.WriteLine("Endpoint {0}",++index); 9: Console.WriteLine("\tAddress: {0}\n\tBinding: {1}\n\tContract: {2}", 10: endpoint.Address, endpoint.Binding, endpoint.Contract.Name); 11: }輸出結果:
1: Endpoint 1 2: Address: http://127.0.0.1/greetingservice 3: Binding: System.ServiceModel.BasicHttpBinding 4: Contract: IHello 5: Endpoint 2 6: Address: http://127.0.0.1/greetingservice 7: Binding: System.ServiceModel.BasicHttpBinding 8: Contract: IGoodbye 9: Endpoint 3 10: Address: net.tcp://127.0.0.1/greetingservice 11: Binding: System.ServiceModel.NetTcpBinding 12: Contract: IHello 13: Endpoint 4 14: Address: net.tcp://127.0.0.1/greetingservice 15: Binding: System.ServiceModel.NetTcpBinding 16: Contract: IGoodbye從輸出的結果我們不難看出,雖然我們沒有以任何形式為寄宿的服務提供終結點,但是WCF會自動為之添加四個默認的終結點。之所以是四個默認終結點,其原因在于:WCF會為服務實現的每一個服務契約基于指定的每一個基地址創建一個終結點。在本例中,服務GreetingService實現了兩個服務契約,在寄宿過程中又為它指定了兩個基地址,所以最終被自動創建的默認終結點是四個。對于自動創建的終結點,其地址和服務契約分別來源于指定的基地址和服務實現的契約,那么采用的綁定又是如何確定的呢?
一、默認終結點的綁定是如何確定的?
從上面的例子我們可以看到,對于自動創建的四個默認終結點,如果采用基于HTTP協議的地址,則采用BasicHttpBinding作為其終結點綁定;如果地址是基于TCP協議的,作為終結點綁定的則為NetTcpBinding。所以說定義在基地址中用以表示傳輸協議的前綴(Scheme)最終決定了采用的綁定類型。
但是,為什么基于HTTP協議的地址采用BasicHttpBinding,而不是WSHttpBinding或者WS2007HttpBinding呢?實際上,基地址的協議類型和最終作為默認終結點的類型之間的匹配關系是通過配置決定的。在<system.serviceModel>配置節中具有一個名為<protocolMapping>的子結點。它包含了一系列用以定義傳輸協議類型(scheme)和綁定類型匹配關系的配置元素。
如果你打開基于.NET Framework 4.0的配置文件machine.config.comments(該配置文件所在的目錄為%Windows%Microsoft.NET\Framework\v4.0.30319\Config),你會發現<protocolMapping>配置節具有如下的定義。具體來說,<protocolMapping>配置節定義了四種傳輸協議(HTTP、TCP、Named Pipe和MSMQ)和對應的綁定類型(BasicHttpBinding、NetTcpBiding、NetNamedPipeBinding和NetMsmqBinding)之間的匹配關系。這實際代表了默認的協議綁定映射關系,這也是為什么在上面的例子中基于HTTP協議的默認終結點會采用BasicHttpBinding作為綁定類型的原因。除了scheme和binding這兩個配置屬性之外,<protocolMapping>的配置元素還具有另外一個額外的配置屬性bindingConfiguration,表示對具體綁定配置的引用。
1: <system.serviceModel> 2: <protocolMapping> 3: <add scheme="http" binding="basicHttpBinding" bindingConfiguration="" /> 4: <add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration=""/> 5: <add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/> 6: <add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/> 7: </protocolMapping> 8: ... 9: </system.serviceModel>如果默認的協議與綁定映射關系不滿足具體應用場景的要求,你可以直接修改machine.config或者基于具體應用的App.config或者Web.config。比如,對于上面的例子,如果為之添加一個配置文件并進行如下的配置:將基于HTTP的綁定類型設置為WS2007HttpBinding。再次運行實例程序,將會發現默認創建的終結點類型發生了相應的改變。
1: <?xml version="1.0"?> 2: <configuration> 3: <system.serviceModel> 4: <protocolMapping> 5: <add scheme="http" binding="ws2007HttpBinding" /> 6: </protocolMapping> 7: </system.serviceModel> 8: </configuration>輸出結果
1: Endpoint 1 2: Address: http://127.0.0.1/greetingservice 3: Binding: System.ServiceModel.WS2007HttpBinding 4: Contract: IHello 5: Endpoint 2 6: Address: http://127.0.0.1/greetingservice 7: Binding: System.ServiceModel.WS2007HttpBinding 8: Contract: IGoodbye 9: Endpoint 3 10: Address: net.tcp://127.0.0.1/greetingservice 11: Binding: System.ServiceModel.NetTcpBinding 12: Contract: IHello 13: Endpoint 4 14: Address: net.tcp://127.0.0.1/greetingservice 15: Binding: System.ServiceModel.NetTcpBinding 16: Contract: IGoodbye二、默認終結點是如何被添加的?
接下來我們來具體介紹默認終結點機制是如何實現的,具體來講就是表示默認終結點的ServiceEndpoint對象是如何被添加到用于表示寄宿服務描述的ServiceDescription的終結點列表(對應于ServiceDescription的Endpoints屬性)中的。要了解默認終結點自動添加的原理,需要涉及到WCF 4.0為ServiceHostBase添加的一個新方法:AddDefaultEndpoints。
1: public abstract class ServiceHostBase : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable 2: { 3: //其他成員 4: public virtual ReadOnlyCollection<ServiceEndpoint> AddDefaultEndpoints(); 5: }從方法名稱我們不難看出,這個方法就是用于實現為ServiceHost添加默認終結點的。從上面給出的關于這個方法的定義我們可以知道這個方法是一個公有方法,可以在具體的服務寄宿應用中被直接調用。當這個方法被調用的時候,WCF會按照我們之前介紹的策略(為指定的每一個基地址和服務實現的契約的組合添加一個終結點,終結點綁定的類型決定于<protocolMapping>配置)進行默認終結點的添加。方法的返回值表示添加的默認終結點集合。
當ServiceHost在開啟的時候,WCF會檢驗其Description熟悉表示的服務描述是否具有至少一個終結點。如果沒有,在會自動調用這個AddDefaultEndpoints方法以添加默認的終結點。比如在下面的代碼片斷中,在開啟ServiceHost之前調用AddServiceEndpoint方法添加了一個終結點,最終默認終結點將不會被添加,所以ServiceHost最終只會有一個唯一的終結點。
1: Uri baseHttpAddress = new Uri("http://127.0.0.1/greetingservice "); 2: Uri baseTcpAddress = new Uri("net.tcp://127.0.0.1/greetingservice "); 3: ServiceHost host = new ServiceHost(typeof(GreetingService), baseHttpAddress, baseTcpAddress); 4: host.AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "manuallyadded"); 5: host.Open(); 6: ...輸出結果:
1: Endpoint 1 2: Address: http://127.0.0.1/greetingservice/manuallyadded 3: Binding: System.ServiceModel.WSHttpBinding 4: Contract: IHello由于公有的AddDefaultEndpoints方法可以手工被調用,所以當你在調用AddServiceEndpoint方法之后再調用該方法,ServiceHost最終將會具有
1: Uri baseHttpAddress = new Uri("http://127.0.0.1/greetingservice "); 2: Uri baseTcpAddress = new Uri("net.tcp://127.0.0.1/greetingservice "); 3: ServiceHost host = new ServiceHost(typeof(GreetingService), baseHttpAddress, baseTcpAddress); 4: host.AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "manuallyadded"); 5: host.AddDefaultEndpoints(); 6: host.Open(); 7: ...輸出結果:
1: Endpoint 1 2: Address: http://127.0.0.1/greetingservice/manuallyadded 3: Binding: System.ServiceModel.WSHttpBinding 4: Contract: IHello 5: Endpoint 2 6: Address: http://127.0.0.1/greetingservice 7: Binding: System.ServiceModel.WS2007HttpBinding 8: Contract: IHello 9: Endpoint 3 10: Address: http://127.0.0.1/greetingservice 11: Binding: System.ServiceModel.WS2007HttpBinding 12: Contract: IGoodbye 13: Endpoint 4 14: Address: net.tcp://127.0.0.1/greetingservice 15: Binding: System.ServiceModel.NetTcpBinding 16: Contract: IHello 17: Endpoint 5 18: Address: net.tcp://127.0.0.1/greetingservice 19: Binding: System.ServiceModel.NetTcpBinding 20: Contract: IGoodbye?
[WCF 4.0新特性] 默認終結點
[WCF 4.0新特性] 默認綁定和行為配置
參考資料:《A Developer's Introduction to Windows Communication Foundation 4》
作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。 原文鏈接
總結
以上是生活随笔為你收集整理的[WCF 4.0新特性] 默认终结点的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [ASP.NET MVC] 利用自定义的
- 下一篇: 【区块链】Truffle 部署 编译 测