什麼是綁定
從本質上說,WCF是一個通信服務框架,它允許我們使用不同 的傳輸協議(如Http、Https、TCP、P2P、IPC和MSMQ等),使用不同的消息編碼 形式(文本、二進制和MTOM),跟不同的WS-*系列規范(如WS-Security、WS- Atomic Transaction等)交互。所有這些細節都是由通道堆棧來處理的,看一下 Aaron Skonnard給出的這幅圖:
圖1
最底層傳輸組件讀入消息,消息編碼器將傳入字節讀取為 邏輯消息對象,之後消息通過通道堆棧中的各個消息,它們執行各自的處理。如 果對這三者之間之間進行組合,至少可以得到上千種不同的通信方式,但是這些 傳輸、編碼以及協議之間有些是互斥的,有些相互約束,也就是說,對於開發人 員來說,每構建一個服務,都要需要考慮這三者之間是否可以共存,是否是高效 的通信方式,顯然這個工作是非常復雜的,要求開發者必須了解所有的傳輸、編 碼以及協議等。
為了簡化這三者之間的管理,WCF中引入了綁定的概念( Binding),每個綁定中都封裝了傳輸協議、消息編碼和多種協議的集合,這樣 在構建服務時,我們就可以直接選擇一個適用的綁定,通過調整它們的屬性來適 應需求,如果系統內置的綁定通過調整屬性仍然不能達到我們的要求,這時才會 考慮自定義綁定。這樣,通過綁定,就把應用程序編程模型與通道模型(後面會 有專門的文章寫到)關聯了起來,對於開發者來說,就無需再考慮復雜的底層通 道模型,直接使用應用程序編程模型。
綁定元素
在WCF中,綁定由綁 定元素組成,每個綁定元素用來描述終結點與客戶端通信方式中的某個方面,綁 定元素繼承於BindingElement,其中最重要的綁定元素有如下三種:
1. 編碼綁定元素(Encoding Binding Element):如采用文本、二進制還是MTOM的 方式;
2.傳輸綁定元素(Transport Binding Element):使用Http、 TCP或者MSMQ進行傳輸;
3.協議綁定元素(Protocol Binding Element) :指定可靠性、安全性、事務等。
每個綁定必須要有一個編碼綁定元素 和一個傳輸綁定元素,以及包括任意數目的其他協議綁定元素。
通道模型中使用綁定
在WCF中,提供了兩個層面的模型,一是針對開發人員的應用程 序編程模型;二是用於通信的通道模型(後面會專門講到)。在通道模型編程中 ,服務端偵聽並接收消息的第一步就是創建綁定,如下面的代碼:
// 創建自定義綁定
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);
這裡創建了一個自定義綁定,並 在其中加入了兩個必須的綁定元素,消息編碼采用文本的方式,而傳輸綁定元素 采用了內置的HttpTransportBindingElement。接下來就可以使用自定義的綁定 來創建通道偵聽器,並進行消息的偵聽,如下代碼所示:
/// <summary>
/// Author:TerryLee
/// Url:http://www.cnblogs.com/terrylee
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// 創建自定義綁定
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);
// 使用自定義綁定創建通道偵聽器
IChannelListener<IReplyChannel> listener =
binding.BuildChannelListener<IReplyChannel>(
new Uri("http://localhost:8080/ChannelApp"),
new BindingParameterCollection());
// 監聽消息
listener.Open();
Console.WriteLine("Listening for incoming channel connections");
IReplyChannel channel = listener.AcceptChannel();
Console.WriteLine("Channel accepted. Listening for messages");
channel.Open();
while (true)
{
RequestContext request = channel.ReceiveRequest();
// 讀取請求的消息
Message message = request.RequestMessage;
Console.WriteLine("Message Received");
Console.WriteLine("Message Action: {0}", message.Headers.Action);
string body = message.GetBody<string>();
Console.WriteLine ("Message Content: {0}", body);
// 發送響應消息
Message replymessage = Message.CreateMessage(
binding.MessageVersion,
"http://www.cnblogs.com/terrylee",
body);
request.Reply(replymessage);
// 釋放 對象
message.Close();
request.Close();
channel.Close();
listener.Close();
}
}
其中的代碼我們就不再解釋,到關於WCF中通道編程模型一文中, 還會進行詳細的講解。
自定義系統綁定
在WCF中,已經內置了大量的 綁定供我們使用,但是如果這些綁定不能滿足實際的開發需求,我們可以通過幾 種辦法來對系統內置綁定進行自定義,一是通過配置文件進行綁定的配置,如下 代碼所示,配置BasicHttpBinding的消息編碼為MTOM,而安全性為消息級別:
<services>
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
behaviorConfiguration="calculatorBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8887/Calculator"/>
</baseAddresses>
</host>
<endpoint address=""
binding ="basicHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
name="defaultBinding"
bindingConfiguration="myBindingConfiguration">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="myBindingConfiguration"
messageEncoding="Mtom">
<security mode="Message"></security>
</binding>
</basicHttpBinding>
</bindings>
二是可以通過編碼的方式,如下代碼所示:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Message.ClientCredentialType =
BasicHttpMessageCredentialType.Certificate;
binding.Security.Mode = BasicHttpSecurityMode.Message;
binding.MessageEncoding = WSMessageEncoding.Mtom;
考慮到程序部署之後的修改,還是推薦使 用配置的方式。同時,我們完全可以利用系統內置綁定創建一個自定義的綁定, 或者我們在自定義綁定過程中,可以直接通過已有的系統內置綁定來創建一個綁 定元素集合,如下代碼所示:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Message.ClientCredentialType =
BasicHttpMessageCredentialType.Certificate;
binding.Security.Mode = BasicHttpSecurityMode.Message;
binding.MessageEncoding = WSMessageEncoding.Mtom;
CustomBinding mybinding = new CustomBinding(binding);
BindingElementCollection myElements =
binding.CreateBindingElements();
在下篇 文章中,我將會介紹如何完全重新進行自定義綁定。
元數據中公開綁定
在WCF中,通信的雙方應該就通信的細節達成一致,既然綁定中封裝了所有通 信的細節,而服務端唯一公開這些細節的方式就是元數據,所以綁定的相關信息 應該通過公開WSDL和 WS-Policy 形式的元數據,這樣服務就可以和客戶端共享 綁定配置,以BasicHttpBinding為例,它所使用的傳輸是Http,而消息編碼采用 文本的方式,如有下面這樣一端配置:
<services>
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
behaviorConfiguration="calculatorBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8887/Calculator"/>
</baseAddresses>
</host>
<endpoint address="http://localhost:8887/CalculatorService"
binding ="basicHttpBinding"
contract="TerryLee.WCFAddressing.Contract.ICalculator"
name="defaultBinding"
bindingConfiguration="myBindingConfiguration">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="myBindingConfiguration"
messageEncoding="Mtom">
</binding>
</basicHttpBinding>
</bindings>
通過綁定配置 ,設置BasicHttpBinding的消息編碼為MTOM,在元數據中,可以看到采用Http進 行傳輸:
<wsdl:binding name="defaultBinding" type="tns:ICalculator">
<wsp:PolicyReference URI="#defaultBinding_policy" />
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Add">
<soap:operation soapAction="http://tempuri.org/ICalculator/Add"
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
對於消息編碼MTOM,放在Policy的配置中 ,如下代碼所示:
<wsp:Policy wsu:Id="defaultBinding_policy">
總結
<wsp:ExactlyOne>
<wsp:All>
<wsoma:OptimizedMimeSerialization
xmlns:wsoma="http://schemas.xmlsoap.org/ws/2004/09/policy/optimiz edmimeserialization" />
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
本文詳細 介紹了WCF中的綁定,以及如何使用綁定進行通信,自定義系統綁定以及在元數 據中公開綁定。