閱讀601 返回首頁    go 技術社區[雲棲]


[WCF REST] WebHttpBinding與消息編碼

不論是我們采用SOAP還是REST架構風格,運行時框架體係依然不曾改變,終結點也仍舊是通信的核心。在Web HTTP編程模型中,我們采用基於WebHttpBinding綁定的終結點。綁定是一組相關綁定元素的有序組合,綁定的特性與能力決定於它包含的綁定元素,在這裏我們通過分析綁定元素的方式來剖析WebHttpBinding綁定與其它綁定有何不同。采用HTTP/HTTPS通信協議的WebHttpBinding具有一些與WSHttpBinding/WS2007HttpBinding相同的屬性,在這裏我們隻關心如下定義的Security屬性。

   1: public class WebHttpBinding : Binding, IBindingRuntimePreferences
   2: {
   3:     //其它成員
   4:     public WebHttpSecurity Security { get; }
   5: }
   6: public sealed class WebHttpSecurity
   7: {
   8:     // 其它成員
   9:     public WebHttpSecurityMode Mode { get; set; }
  10:     public HttpTransportSecurity Transport { get; }
  11: }
  12: public enum WebHttpSecurityMode
  13: {
  14:     None,
  15:     Transport,
  16:     TransportCredentialOnly
  17: }

基於SOAP的綁定一般具有兩種基本的安全模式,即Message和Transport模式。對於前者,它是完全建立在WS-Security為核心的安全協議之上的,而整個WS-*協議簇都是基於SOAP的,所以自然不能應用在WebHttpBinding上,所以它隻能通過HTTPS提供針對Transport模式的安全支持。具體來說,通過枚舉WebHttpSecurityMode表示的安全模式具有如下三個選項:

  • None:HTTP 請求未使用任何安全性;
  • Transport:HTTP 請求使用傳輸級安全性;
  • TransportCredentialOnly:僅提供基於 HTTP 的客戶端身份驗證。

現在我們根據上述三種不同的安全模式創建相應的WebHttpBinding對象,然後通過如下的程序在控製台中答應出所有的綁定元素類型。

   1: static void Main(string[] args)
   2: {
   3:     WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.None);
   4:     ListBindingElements(binding);
   5:  
   6:     binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
   7:     ListBindingElements(binding);
   8:  
   9:     binding = new WebHttpBinding(WebHttpSecurityMode.TransportCredentialOnly);
  10:     ListBindingElements(binding);
  11: }
  12: static void ListBindingElements(WebHttpBinding binding)
  13: {
  14:     int index = 1;
  15:     Console.WriteLine(binding.Security.Mode + ":");
  16:     foreach (var element in binding.CreateBindingElements())
  17:     { 
  18:         Console.WriteLine("{0}. {1}", index++, element.GetType().FullName);
  19:     }
  20:     Console.WriteLine();
  21: }

上述的程序執行之後會在控製台上產生如下的輸出,從中我們不難看出三個WebHttpBinding均由一個消息編碼元素和傳輸元素組成,我們知道這兩種綁定元素最所有類型的綁定所必需的。

   1: None:
   2: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
   3: 2. System.ServiceModel.Channels.HttpTransportBindingElement
   4:  
   5: Transport:
   6: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
   7: 2. System.ServiceModel.Channels.HttpsTransportBindingElement
   8:  
   9: TransportCredentialOnly:
  10: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
  11: 2. System.ServiceModel.Channels.HttpTransportBindingElement

對於WebHttpBinding的兩個綁定元素來說,由於它通過HTTPS提供針對Transport安全的支持,所以當安全模式為Transport時對應的傳輸綁定元素為HttpsTransportBindingElement,對於其餘兩種安全模式則直接采用HttpTransportBindingElement作為傳輸綁定元素。現在我們著重討論是作為消息編碼綁定元素的WebMessageEncodingBindingElement類型,以及它涉及的消息編碼機製。

我們先來看看WebMessageEncodingBindingElement的基本的定義。如下麵的代碼片斷所示,它是MessageEncodingBindingElement的子類,並且具有與TextMessageEncodingElement類似的屬性定義。其中MaxReadPoolSize和MaxWritePoolSize表示表示無需分配新的XmlDictionaryReader/XmlDictionaryWriter便可以讀取的便可同時讀取/寫入的最大消息數,默認值分別是64和16。ReaderQuotas屬性返回用於約束讀取的XML的複雜度的XmlDictionaryReaderQuotas對象,而WriteEncoding屬性表示采用的字符編碼類型,默認采用UTF-8編碼方式。由於WebHttpBinding不使用SOAP,表示消息版本的MessageVersion屬性自然返回None,如果我們對該屬性進行設置,指定的屬性值也隻能是MessageVersion.None。

   1: public sealed class WebMessageEncodingBindingElement : MessageEncodingBindingElement,...
   2: {   
   3:     //其它成員
   4:     public override MessageEncoderFactory CreateMessageEncoderFactory();
   5:  
   6:     public bool CrossDomainScriptAccessEnabled {get; set; } 
   7:     public WebContentTypeMapper ContentTypeMapper { get; set; }
   8:  
   9:     public int MaxReadPoolSize { get; set; }
  10:     public int MaxWritePoolSize { get; set; }
  11:     public override MessageVersion MessageVersion { get; set; }
  12:     public XmlDictionaryReaderQuotas ReaderQuotas { get; }
  13:     public Encoding WriteEncoding { get; set; }
  14: }

除此之外,WebMessageEncodingBindingElement具有CrossDomainScriptAccessEnabled 和ContentTypeMapper這兩個重要的屬性。前者表示是否支持跨域(Corss-Domain)腳本訪問,默認值為False。後者類型為WebContentTypeMapper。WebContentTypeMapper用於進行消息的內容類型(Content Type,有時候也成為媒體類型或者MIME類型)與具體的格式(比如XML、JSON等)之間的映射。

   1: public abstract class WebContentTypeMapper
   2: {
   3:     protected WebContentTypeMapper();
   4:     public abstract WebContentFormat GetMessageFormatForContentType(string contentType);
   6: }
   7: public enum WebContentFormat
   8: {
   9:     Default,
  10:     Xml,
  11:     Json,
  12:     Raw
  13: }

如上麵的代碼所示,WebContentTypeMapper是一個抽象類,包含的唯一的抽象方法GetMessageFormatForContentType用於根據指定的內容類型返回與之匹配的通過枚舉WebContentFormat表示的內容格式。WebContentFormat枚舉的Xml、JSON和Raw體現了Web HTTP編程模型支持三種基本格式,其中Raw表示原始的二進製。

最終的消息編碼/解碼工作是通過繼承自MessageEncoder的消息編碼器實現的,消息編碼器又是通過繼承自MessageEncoderFactory的編碼器工廠創建出來的,而消息編碼綁定元素最終通過方法CreateMessageEncoderFactory創建了編碼器工廠。對於WebMessageEncodingBindingElement來說,它的CreateMessageEncoderFactory方法會創建一個具有如下定義的WebMessageEncoderFactory對象。

   1: internal class WebMessageEncoderFactory : MessageEncoderFactory
   2: {
   3:     public WebMessageEncoderFactory(Encoding writeEncoding, int maxReadPoolSize,int maxWritePoolSize, XmlDictionaryReaderQuotas quotas, 
   4:         WebContentTypeMapper contentTypeMapper, bool javascriptCallbackEnabled);
   5:     public override MessageEncoder Encoder { get; }
   6:     public override MessageVersion MessageVersion { get; }
   7: }
   8:   

WebMessageEncoderFactory是一個繼承自MessageEncoderFactory的內部類型。除了布爾類型的參數javascriptCallbackEnabled對應著WebMessageEncodingBindingElement的屬性CrossDomainScriptAccessEnabled之外,WebMessageEncoderFactory的構造函數參數與WebMessageEncodingBindingElement的同名屬性一一對應。代表消息版本的MessageVersion屬性依然返回None,而真正用於最終消息編碼/解碼工作的是通過Encoder屬性返回的具有如下定義的WebMessageEncoder對象。

   1: internal class WebMessageEncoderFactory : MessageEncoderFactory
   2: {    
   3:     private class WebMessageEncoder : MessageEncoder
   4:     {
   5:         //其他成員
   6:         private MessageEncoder TextMessageEncoder { get; }
   7:         private MessageEncoder JsonMessageEncoder { get; }
   8:         private MessageEncoder RawMessageEncoder { get; }
   9:     }
  10: }

如上麵的代碼片斷所示,WebMessageEncoder實際上是內嵌於WebMessageEncoderFactory類型中繼承自MessageEncoder的內部類型。WebMessageEncoder本身並不真正地實施消息的編碼/解碼,最終的消息編碼/解碼工作是通過三個屬性TextMessageEncoder、JsonMessageEncoder和RawMessageEncoder體現的具體消息編碼器完成的,而它們又分別對應著通過WebContentFormat枚舉表示的三種內容類型Xml、JSON和Raw。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 14:04:21

  上一篇:go  [WCF REST] 一個簡單的REST服務實例
  下一篇:go  網站托管:關鍵詞內頁排名怎麼做好?