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


[WCF REST] 幫助頁麵與自動消息格式(JSON/XML)選擇

可以說WebHttpBinding和WebHttpBehavior是整個Web HTTP編程模型最為核心的兩個類型,前者主要解決消息編碼問題,而餘下的工作基本上落在了終結點行為WebHttpBehavior上。WebHttpBehavior屬性HelpEnabled和AutomaticFormatSelectionEnabled是“幫助頁麵”與“自動消息格式選擇”這兩個特性的總開關。[“自動消息格式(JSON/XML)選擇”源代碼從這裏下載]

   1: public class WebHttpBehavior : IEndpointBehavior, ...
   2: {
   3:     //其他成員    
   4:     public virtual bool HelpEnabled { get; set; }
   5:     public virtual bool AutomaticFormatSelectionEnabled { get; set; }
   6: }

WCF 4.0為REST服務提供了幫助頁麵功能,我們可以通過瀏覽器訪問服務幫助頁麵的地址得到所有操作的基本信息。但是這個功能在默認的情況下是關閉的,我們需要通過應用在終結點上的WebHttpBehavior行為的HelpEnabled屬性開啟該功能。

   1: <configuration>
   2:     <system.serviceModel>
   3:         <behaviors>
   4:             <endpointBehaviors>
   5:                <behavior>
   6:                    <webHttp helpEnabled="true" />
   7:                </behavior>
   8:             </endpointBehaviors>
   9:         </behaviors>
  10:         <services>
  11:             <service name="Artech.WcfServices.Service.EmployeesService">
  12:                 <endpoint address="https://127.0.0.1:3721/employees"
  13:                           binding="webHttpBinding" 
  14:                           contract="Artech.WcfServices.Service.Interface.IEmployees"/>
  15:             </service>
  16:         </services>
  17:     </system.serviceModel>
  18: </configuration>

同樣以之前演示的EmployeesService為例,我們通過如上的配置將終結點行為WebHttpHehavior應用在服務唯一的終結點上(默認終結點),並將HelpEnabled屬性設置為True。那麼基於終結點的幫助頁麵將以地址發布出來,我們通過瀏覽器訪問這個地址就會得到如下圖所示幫助頁麵。

image

如上圖所示,幫助頁麵列出了包括相對地址、HTTP方法和基本描述在內的所有操作的基本信息。我們通過點擊HTTP方法對應的鏈接可以獲得包括基於相應格式(Xml和Json)消息結構(Schema)和實例。在默認的情況下,幫助頁麵中表示操作描述信息的格式為“我們可以在定義服務契約的時候再操作方法上應用特性DescriptionAttribute來定義出現在幫助頁麵中的描述信息。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     [WebGet(UriTemplate = "all")]
   5:     [Description("獲取所有員工列表")]
   6:     IEnumerable<Employee> GetAll();
   7:  
   8:     [WebGet(UriTemplate = "{id}")]
   9:     [Description("獲取指定ID的員工")]
  10:     Employee Get(string id);
  11:  
  12:     [WebInvoke(UriTemplate = "/", Method = "POST")]
  13:     [Description("創建一個新的員工")]
  14:     Employee Create(Employee employee);
  15:  
  16:     [WebInvoke(UriTemplate = "/", Method = "PUT")]
  17:     [Description("修改現有員工信息")]
  18:     void Update(Employee employee);
  19:  
  20:     [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
  21:     [Description("刪除指定ID的員工")]
  22:     void Delete(string id);
  23: }

如上麵的代碼片斷所示,我們在契約接口IEmployees中的所有操作方法上應用了DescriptionAttribute特性並指定了相應的描述信息。這些描述信息就是出現在如下圖所示的幫助頁麵中。

image

REST服務具有兩種基本的消息格式(Xml和Json)。在定義服務契約的時候,我們可以通過應用在操作方法上的WebGetAttribute和WebInvokeAttribute指定回複消息的格式。如果沒有通過這種方式對消息格式進行顯式設置,我們還可以通過終結點行為WebHttpBehavior為回複消息設置一個默認的消息格式。除了這種顯示設置方式之外,WCF還提供一種自動消息格式選擇機製。

所謂消息格式的自動選擇,就是服務根據請求消息來選擇一種適合的格式進行消息的序列化。在默認的情況下,這種自動選擇機製是關閉的,我們需要通過WebHttpBehavior的AutomaticFormatSelectionEnabled屬性開啟該機製。具體的消息格式選擇機製策略(順序)如下:

  • 如果作為請求的HTTP消息具有報頭,則根據該報頭決定回複消息的格式;
  • 如果作為請求的HTTP消息具有報頭,則根據該報頭決定回複消息的格式;
  • 如果在定義服務契約時通過對回複消息的格式進行了顯式設置,則采用該消息格式;
  • 如果通過終結點行為設置了對回複消息的格式進行了顯式設置,則采用該消息格式;
  • 采用默認消息格式(WebMessageFormat枚舉的默認值)。

我們同樣通過之前創建的EmployeesService的實例來演示消息格式的自動選擇機製。如下麵的配置片斷所示,我們將WebHttpBehavior行為應用到了寄宿服務的唯一終結點上,並且將AutomaticFormatSelectionEnabled屬性設置為True。

   1: <configuration>
   2:     <system.serviceModel>
   3:         <behaviors>
   4:             <endpointBehaviors>
   5:                 <behavior name="webHttp">
   6:                     <webHttp automaticFormatSelectionEnabled="true" />
   7:                 </behavior>
   8:             </endpointBehaviors>
   9:         </behaviors>
  10:     <services>
  11:         <service name="Artech.WcfServices.Service.EmployeesService">
  12:             <endpoint address="https://127.0.0.1:3721/employees" 
  13:                       behaviorConfiguration="webHttp"
  14:                       binding="webHttpBinding"  
  15:                       contract="Artech.WcfServices.Service.Interface.IEmployees"/>
  16:             </service>
  17:         </services>
  18:     </system.serviceModel>
  19: </configuration>

對於契約接口IEmployees來說,我們通過WebGetAttribute特性用於返回所有員工列表的GetAll操作的回複消息格式設置為Xml。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     //其他成員
   5:     [WebGet(UriTemplate = "all",ResponseFormat = WebMessageFormat.Xml)]
   6:     IEnumerable<Employee> GetAll();
   7: }

對於REST服務調用來說,其本質就是一種普通的HTTP請求,與針對某個網頁的訪問並沒有什麼本質的不同,所以我們完全可以手工生成HTTP請求來進行服務的訪問。為此我們創建了如下一個靜態方法GetAllEmployees方法通過WebClient對服務的GetAll操作進行調用,並將整個回複消息打印出來,該方法的兩個參數分別是作為請求的HTTP消息的Content-Type和Accept報頭值。

   1: static void GetAllEmployees(string contentType, string accept)
   2: {
   3:     WebClient webClient = new WebClient();
   4:     if (!string.IsNullOrEmpty(contentType))
   5:     {
   6:         webClient.Headers.Add("Content-Type", contentType);
   7:     }
   8:  
   9:     if (!string.IsNullOrEmpty(accept))
  10:     {
  11:         webClient.Headers.Add("Accept", accept);
  12:     }
  13:     using (StreamReader reader = new StreamReader(webClient.OpenRead(
  14:         "https://127.0.0.1:3721/employees/all")))
  15:     {
  16:         Console.WriteLine(reader.ReadToEnd());
  17:     }
  18: }

然後我們通過調用GetAllEmployees方法進行三次服務調用。第一次調用既沒有指定Content-Type報頭也沒有指定Accept報頭,第二次和第三次調用在分別將這兩個報頭指定為“application/json”。

   1: string contentType = "application/json";
   2:  
   3: Console.WriteLine("Content-Type = N/A; Accept = N/A:");
   4: GetAllEmployees("", "");
   5: Console.WriteLine();
   6:  
   7: Console.WriteLine("Content-Type = application/json; Accept = N/A:");
   8: GetAllEmployees(contentType, "");
   9: Console.WriteLine();
  10:  
  11: Console.WriteLine("Content-Type = N/A, Accept = application/json:");
  12: GetAllEmployees("", contentType);

從如下所示的輸出結果我們可以看出:由於服務調用請求沒有指定任何媒體類型相關的報頭,所以回複消息采用的是契約接口中設置的消息格式Xml。對於後兩次服務調用中,由於請求消息中分別通過Content-Type和Accept報頭將“期望”的媒體類型設置為application/json,所以Json最終作為回複消息的格式。(S1006)

   1: Content-Type = N/A; Accept = N/A:
   2: <ArrayOfEmployee xmlns="http://www.artech.com/" xmlns:i="https://www.w3.org/2001/
   3: XMLSchema-instance"><Employee><Department>開發部</Department><Grade>G7</Grade><I
   4: d>001</Id><Name>張三</Name></Employee><Employee><Department>人事部</Department><
   5: Grade>G6</Grade><Id>002</Id><Name>李四</Name></Employee></ArrayOfEmployee>
   6:  
   7: Content-Type = application/json; Accept = N/A:
   8: [{"Department":"開發部","Grade":"G7","Id":"001","Name":"張三"},{"Department":"人
   9: 事部","Grade":"G6","Id":"002","Name":"李四"}]
  10:  
  11: Content-Type = N/A, Accept = application/json:
  12: [{"Department":"開發部","Grade":"G7","Id":"001","Name":"張三"},{"Department":"人
  13: 事部","Grade":"G6","Id":"002","Name":"李四"}]

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

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

  上一篇:go  [WCF REST] Web消息主體風格(Message Body Style)
  下一篇:go  [WCF REST] WebServiceHost有何特別之處?