[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="http://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。那么基於終結點的幫助頁面將以地址{終結點地址}/Help發布出來,我們通過瀏覽器訪問這個地址就會得到如下圖所示幫助頁面。

image

如上圖所示,幫助頁面列出了包括相對地址、HTTP方法和基本描述在內的所有操作的基本信息。我們通過點擊HTTP方法對應的鏈接可以獲得包括基於相應格式(Xml和Json)消息結構(Schema)和實例。在默認的情況下,幫助頁面中表示操作描述信息的格式為“Service at {操作地址}”,我們可以在定義服務契約的時候再操作方法上應用特性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消息具有Accept報頭,則根據該報頭決定回復消息的格式;
  • 如果作為請求的HTTP消息具有Content-Type報頭,則根據該報頭決定回復消息的格式;
  • 如果在定義服務契約時通過WebGetAttribute或者WebInvokeAttribute對回復消息的格式進行了顯式設置,則采用該消息格式;
  • 如果通過終結點行為WebHttpBehavior設置了對回復消息的格式進行了顯式設置,則采用該消息格式;
  • 采用默認消息格式Xml(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="http://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:         "http://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="http://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":"李四"}]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM