.Net Framework 4.5與Visual Studio 11 - WCF Web API (4)

by vivid 29. 二月 2012 01:38

.NET Magazine國際中文電子雜誌
者:許薰尹
稿:張智凱
文章編號:N120212103
出刊日期:2012/02/29

本文延續《.Net Framework 4.5與Visual Studio 11 - WCF Web API (3)》一文的內容來探討WCF Web API提供的新功能,利用Visual Studio 11 Developer Preview開發工具來開發服務程式碼,讓你更容易設計支援REST類型的WCF服務。由於本文撰寫時使用的工具是Visual Studio 11 Developer Preview,而WCF Web API 則是Preview 6版,因此本文探討的內容在正式版上市時可能不適用。

延續前一篇文章《.Net Framework 4.5與Visual Studio 11 - WCF Web API (3)》的情境,介紹序列化的注意事項。

XML序列化

WCF Web API內建了將CLR物件序列化成XML或JSON格式,並將序列化完的結果放在HTTP封包Body區段回傳。舉例來說,若使用HTTP GET 動詞,連結到本文服務範例,在WCF Web API Test Client工具程式中,使用以下URI取回員工代號2號的資料回來:

http://localhost:4462/api/employees/2

預設WCF Web API使用XmlSerializer類別來處理XML序列化的動作。若HTTP Headers 設定為「Accept:*/*」,得到的HTTP回應如下,HTTP請求的Content-Type會是「application/xml」:

Response 200/OK
Headers
Cache-Control: private
Content-Length: 218
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXNcMg==?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 04:35:00 GMT

 
Body
<?xml version="1.0" encoding="utf-8"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EmployeeID>2</EmployeeID>
  <EmployeeName>Candy</EmployeeName>
</Employee>


因預設WCF Web API將CLR物件為XML格式,因此將HTTP Headers 設定為「Accept:*/*」和設定為「設定為Accept:application/xml」會得到相同的執行結果。

若我們將HTTP Accept Header設定為「application/json」,再送出HTTP 請求進行測試,則回傳的結果為JSON格式的資料。參考以下執行結果,Content-Type設定為「application/json」,Body區段的物件會以JSON格式描述:

Response 200/OK
Headers
Cache-Control: private
Content-Length: 39
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXNcMg==?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 04:45:09 GMT

 
Body
{
  "EmployeeID":2,
  "EmployeeName":"Candy"
}


若我們將HTTP Accept Header設定為「text/json」,再送出HTTP 請求進行測試,則Content-Type為「text/json」,回傳的結果也會是JSON格式的資料,參考以下執行結果:

Response 200/OK
Headers
Cache-Control: private
Content-Type: text/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXNcMg==?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 04:47:50 GMT

 
Body
{
  "EmployeeID":2,
  "EmployeeName":"Candy"
}


客製化XML 序列化

由於WCF Web API預設使用XmlSerializer類別來處理XML序列化的動作,若想要客製化XML序列化的過程,可以利用定義在System.Runtime.Serialization命名空間下的Attribute,例如修改Employee類別定義,在類別上方套用XmlRoot Attribute,自訂根標籤的名稱為「MyEmployee」,EmployeeID屬性將會以XML Attribute的型式出現在根開頭標籤,名稱將會是「EmpID」;EmployeeName屬性將會以XML Element方式顯示,名稱將會是「EmpName」。


[XmlRoot("MyEmployee")]
public class Employee
{
     [XmlAttribute("EmpID")]
     public int EmployeeID { get; set; }
     [XmlElement("EmpName")]
     public string EmployeeName { get; set; }
}

 

在WCF Web API Test Client工具程式中,使用以下URI取回員工代號2號的資料回來:http://localhost:4462/api/employees/2

則執行的結果如下所示:

Response 200/OK
Headers
Cache-Control: private
Content-Length: 196
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXNcMg==?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 05:00:02 GMT

 
Body
<?xml version="1.0" encoding="utf-8"?>
<MyEmployee EmpID="2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EmpName>Candy</EmpName>
</MyEmployee>


為了測試XmlSerializer的序列化動作,我們再修改一下程式碼,為Employee類別新增一個Age欄位,為測試緣故,此範例直接寫死Age為30:

[XmlRoot ( "MyEmployee" )]
  public class Employee
  {
      [XmlAttribute ( "EmpID" )]
      public int EmployeeID { get; set; }
      [XmlElement ( "EmpName" )]
      public string EmployeeName { get; set; }
      [XmlElement ( "Age" )]
      public int Age = 30;
  }

在WCF Web API Test Client工具程式中,使用以下URI取回員工代號大於2號的資料回來:http://localhost:4462/api/employees?id=2

執行的結果如下所示,每個員工的Age都被設定為30:

Response 200/OK
Headers
Cache-Control: private
Content-Length: 307
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXM=?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 05:21:18 GMT

 
Body
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Employee EmpID="2">
    <Age>30</Age>
    <EmpName>Candy</EmpName>
  </Employee>
  <Employee EmpID="3">
    <Age>30</Age>
    <EmpName>Judy</EmpName>
  </Employee>
</ArrayOfEmployee>

但若修改Employee類別,將Age的成員存取修飾詞(Access Modifier)修為private,再進行相同的測試動作:

[XmlRoot ( "MyEmployee" )]
  public class Employee
  {
      [XmlAttribute ( "EmpID" )]
      public int EmployeeID { get; set; }
      [XmlElement ( "EmpName" )]
      public string EmployeeName { get; set; }
      [XmlElement ( "Age" )]
      private int Age = 30;
  }

 

得到的結果如下,比對上一個範例的結果,你將發現Age的資料並不在回傳的HTTP封包Body的區段中。這是因為預設XmlSerializer只序列化public成員,不序列化private成員的緣故。

Response 200/OK
Headers
Cache-Control: private
Content-Length: 281
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXM=?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 05:22:24 GMT

 
Body
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Employee EmpID="2">
    <EmpName>Candy</EmpName>
  </Employee>
  <Employee EmpID="3">
    <EmpName>Judy</EmpName>
  </Employee>
</ArrayOfEmployee>


若希望private成員也被序列化,這時您可以改用其它的.NET類別來處理,例如改用DataContractSerializer進行序列化。

使用DataContractSerializer序列化

若要修改預設WCF Web API使用XmlSerializer類別序列化CLR物件的行為,改用DataContractSerializer類別來序列化,首先需要修改類別的定義,在類別的上方套用DataContract Attribute,並在類別中所有需要序列化的成員上方套用DataMember Attribute:

[DataContract]
    public class Employee
    {
       [DataMember]
        public int EmployeeID { get; set; }
        [DataMember]
        public string EmployeeName { get; set; }
        [DataMember]
        private int Age = 30;
    }

接著還需要利用HttpConfiguration類別來啟用DataContractSerializer的功能,在Application_Start方法中,加入以下程式碼,將HttpConfiguration. Formatters.XmlFormatter.UseDataContractSerializer屬性設定為「true」。

protected void Application_Start ( )
        {

            var config = new HttpConfiguration ( ) { EnableTestClient = true };
            config.Formatters.XmlFormatter.UseDataContractSerializer = true;
            _factory = new HttpServiceHostFactory ( ) { Configuration = config };
            RouteTable.Routes.Add ( new ServiceRoute ( "api" , _factory , typeof ( EmployeeService ) ) );

        }

在WCF Web API Test Client工具程式中,使用以下URI取回員工代號大於2號的資料回來:http://localhost:4462/api/employees?id=2

則執行的結果如下所示,Age欄位將會被序列化:

Response 200/OK
Headers
Cache-Control: private
Content-Length: 338
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcdGVtcFxNdmNBcHBsaWNhdGlvbjFcTXZjQXBwbGljYXRpb24xXGFwaVxlbXBsb3llZXM=?=
X-Powered-By: ASP.NET
Date: Thu, 15 Dec 2011 05:25:59 GMT

 
Body
<ArrayOfEmployee xmlns="http://schemas.datacontract.org/2004/07/MvcApplication1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Employee>
    <Age>30</Age>
    <EmployeeID>2</EmployeeID>
    <EmployeeName>Candy</EmployeeName>
  </Employee>
  <Employee>
    <Age>30</Age>
    <EmployeeID>3</EmployeeID>
    <EmployeeName>Judy</EmployeeName>
  </Employee>
</ArrayOfEmployee>

Tags:

.NET Magazine國際中文電子雜誌 | WCF Web API | Visual Studio | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List