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


[WCF REST] Web消息主體風格(Message Body Style)

對於Web HTTP編程模型來說,服務契約中作為操作的方法無須應用OperationContractAttribute特性,隻需要根據需要應用WebGetAttribute與WebInvokeAttribute特性即可。前者針對GET HTTP方法,或者則針對其他HTTP方法。WebGetAttribute與WebInvokeAttribute的屬性BodyStyle和IsBodyStyleSetExplicitly涉及到“Web消息主體風格”的話題。

   1: [AttributeUsage(AttributeTargets.Method)]
   2: public sealed class WebGetAttribute : Attribute, IOperationBehavior
   3: {
   4:     //其他成員
   5:     public WebMessageBodyStyle BodyStyle { get; set; }
   6: }
   7:  
   8: [AttributeUsage(AttributeTargets.Method)]
   9: public sealed class WebInvokeAttribute : Attribute, IOperationBehavior
  10: {
  11:     //其他成員
  12:     public WebMessageBodyStyle BodyStyle { get; set; }
  13: }

至於消息主體的風格通過具有如下定義的枚舉WebMessageBodyStyle表示。

   1: public enum WebMessageBodyStyle
   2: {
   3:     Bare,
   4:     Wrapped,
   5:     WrappedRequest,
   6:     WrappedResponse
   7: }

我們知道請求消息和回複消息分別是對操作方法輸入參數和返回值(輸出參數和引用參數)的封裝,WebMessageBodyStyle中的Bare表示請求消息和回複消息的主體部分僅僅包含針對輸入參數和返回值(輸出參數和引用參數)序列化後的內容,而Wrapped則會在外麵包裝一個基於當前操作的“封套”。枚舉項WrappedRequest和WrappedResponse用於單獨針對請求消息和回複消息的主體進行封裝。

WebGetAttribute與WebInvokeAttribute的屬性BodyStyle的默認值為Bare。如果該屬性被設置成WrappedRequest,則回複消息主體依然采用Bare風格;如果該屬性被設置成WrappedResponse,則請求消息主體依然采用Bare風格。布爾類型的隻讀屬性IsBodyStyleSetExplicitly表示是否針對屬性BodyStyle進行了顯示設置。

目錄
一、Xml+Bare
二、Xml+Wrapped
三、JSON+Bare
四、JSON+Wrapped
五、Bare請求消息風格對單一輸入的限製
六、Bare回複消息風格對單一輸出的限製

我們通過之前演示的實例來看看針對不同的消息格式(XML和JSON),請求消息和回複消息的主體在采用不同風格的情況下具有怎樣的結構。現在我們對應用在契約接口IEmployees中的Create操作方法上的WebInvokeAttribute進行了如下的修改,即顯式地指定了請求消息和回複消息的格式(XML)和主體風格()。同時也將返回類型從void編程了Employee,並直接將創建的Employee對象返回。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     //其他成員
   5:     [WebInvoke(UriTemplate = "/", Method = "POST", 
   6:     RequestFormat = WebMessageFormat.Xml, 
   7:     ResponseFormat = WebMessageFormat.Xml, 
   8:     BodyStyle = WebMessageBodyStyle.Bare)]
   9:     Employee Create(Employee employee);
  10: }
  11:  
  12: public class EmployeesService : IEmployees
  13: {
  14:     //其他成員
  15:     public Employee Create(Employee employee)
  16:     {
  17:         employees.Add(employee);
  18:         return employee;
  19:     }
  20: }

我們針對如下所示的代碼通過服務調用添加一個姓名為“王五”的員工。

   1: using (ChannelFactory<IEmployees> channelFactory = new ChannelFactory<IEmployees>("employeeService"))
   2: {
   3:     IEmployees proxy = channelFactory.CreateChannel();
   4:     proxy.Create(new Employee
   5:     {
   6:         Id         = "003",
   7:         Name       = "王五",
   8:          Grade     = "G9",
   9:         Department = "行政部"
  10:     });           
  11: }

針對如上所示的服務調用,由於消息格式和主體風格分別為Xml和Bare,所以作為請求消息和回複消息的主體僅僅是Employee對象被序列化後生成的XML片斷,具體內容如下所示。

   1: 請求消息主體:
   2: <Employee xmlns="https://www.artech.com/" 
   3:   xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
   4:   <Department>行政部</Department>
   5:   <Grade>G9</Grade>
   6:   <Id>003</Id>
   7:   <Name>王五</Name>
   8: </Employee>
   9:  
  10: 回複消息主體:
  11: <Employee xmlns="https://www.artech.com/" 
  12:   xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
  13:   <Department>行政部</Department>
  14:   <Grade>G9</Grade>
  15:   <Id>003</Id>
  16:   <Name>王五</Name>
  17: </Employee>

現在我們對契約接口略加修改,將應用在操作方法Create上的WebInvokeAttribute特性的屬性BodyStyle設置為。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     //其他成員
   5:     [WebInvoke(UriTemplate = "/", Method = "POST", 
   6:     RequestFormat = WebMessageFormat.Xml, 
   7:     ResponseFormat = WebMessageFormat.Xml, 
   8:     BodyStyle = WebMessageBodyStyle.Wrapped)]
   9:     Employee Create(Employee employee);
  10: }

針對相同的服務調用,請求消息和回複消息將具有如下所示的主體內容。我們可以看出Employee被序列化後生成的XML在請求消息中作為<Create>元素的子元素;對於回複消息來說,Employee被序列化後生成的XML的根元素名稱為CreateResult,而不是<Employee>,而整個<CreateResult>內嵌於< CreateResponse >元素中。

   1: 請求消息主體:
   2: <Create xmlns="https://tempuri.org/">
   3:   <employee xmlns:a="https://www.artech.com/" 
   4:         xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
   5:     <a:Department>行政部</a:Department>
   6:     <a:Grade>G9</a:Grade>
   7:     <a:Id>003</a:Id>
   8:     <a:Name>王五</a:Name>
   9:   </employee>
  10: </Create>
  11:  
  12: 回複消息主體:
  13: <CreateResponse xmlns="https://tempuri.org/">
  14:   <CreateResult xmlns:a="https://www.artech.com/" 
  15:         xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
  16:     <a:Department>行政部</a:Department>
  17:     <a:Grade>G9</a:Grade>
  18:     <a:Id>003</a:Id>
  19:     <a:Name>王五</a:Name>
  20:   </CreateResult>
  21: </CreateResponse>

上麵我們通過實例演示了消息格式為Xml情況下針對不同風格的消息主體的內容差異,現在我們按照相同的方式來討論當消息格式為JSON的時候,針對不同風格的消息主體在結構上又具有怎樣差異。如下麵的代碼片斷所示,我們通過對契約接口的修改將服務操作Create的消息格式和主體風格設置成。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     //其他成員
   5:     [WebInvoke(UriTemplate = "/", Method = "POST", 
   6:     RequestFormat = WebMessageFormat.Json, 
   7:     ResponseFormat = WebMessageFormat.Json, 
   8:     BodyStyle = WebMessageBodyStyle.Bare)]
   9:     Employee Create(Employee employee);
  10: }

同樣針對之前的服務調用,以JSON形式表示的Employee對象將直接作為請求消息和回複消息的主體部分,具體的內容如下所示。(S1004)

   1: 請求消息主體:
   2: {"Department":"行政部","Grade":"G9","Id":"003","Name":"王五"}
   3:  
   4: 回複消息主體:
   5: {"Department":"行政部","Grade":"G9","Id":"003","Name":"王五"}

我們最後來演示Json消息格式在Wrapped風格下具有怎樣的結構,為此我們隻需要將應用在Create操作方法上的WebInvokeAttribute特性的BodyStyle屬性設置為Wrapped。

   1: [ServiceContract]
   2: public interface IEmployees
   3: {
   4:     //其他成員
   5:     [WebInvoke(UriTemplate = "/", Method = "POST", 
   6:     RequestFormat = WebMessageFormat.Json, 
   7:     ResponseFormat = WebMessageFormat.Json, 
   8:     BodyStyle = WebMessageBodyStyle.Wrapped)]
   9:     Employee Create(Employee employee);
  10: }

如下麵的代碼所示,由於請求消息和回複消息采用Wrapped風格,表示Employee的JSON對象最終作為最終JSON對象的“employee”屬性和“CreateResult”屬性。(S1005)

   1: 請求消息主體:
   2: {"employee":{"Department":"行政部","Grade":"G9","Id":"003","Name":"王五"}}
   3:  
   4: 回複消息主體:
   5: {"CreateResult":{"Department":"行政部","Grade":"G9","Id":"003","Name":"王五"}}

對於Bare消息主體風格來說,意味著對象被序列化後生成的XML或者JSON表示直接作為消息的主體,所以隻適用於單一對象。具體來說,隻有具有唯一輸入參數的操作方法才能將請求消息的主題風格設置為Bare。

   1: [ServiceContract(Namespace = "https://www.artech.com/")]
   2: public interface ICalculator
   3: {
   4:     [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare)]
   5:     double Add( double x,  double y);
   6: }

如上所示的是我們熟悉的計算服務的契約接口的定義。消息主體風格為Bare的操作方法Create具有兩個輸入參數(x和y),在對實現了該契約接口進行寄宿的時候就會拋出如下圖所示的InvalidOperationException異常,提示“”。

image

由於回複參數是對返回值、引用參數和輸出參數的封裝,所以當操作方法具有引用參數或者輸出參數時不能將回複消息的主體風格設置為Bare。

   1: [ServiceContract(Namespace = "https://www.artech.com/")]
   2: public interface ICalculator
   3: {    
   4:     [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
   5:     void Add( double x,  double y, out double result);
   6: }

同樣以計算服務契約為例,現在我們通過如上的方式以輸出參數的形式返回加法運算的結果,並將應用在操作方法上的WebInvokeAttribute特性的BodyStyle屬性設置為WrappedRequest,這意味著請求消息和回複消息分別采用Wrapped和Bare風格。當我們對實現了該契約接口的服務設施寄宿時會拋出下圖所示的InvalidOperationException異常,並提示“”。

image


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

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

  上一篇:go  網站托管:關鍵詞內頁排名怎麼做好?
  下一篇:go  [WCF REST] 幫助頁麵與自動消息格式(JSON/XML)選擇