首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 序列化深度解析(四):DataContractSerializer 核心機制與實戰(上)

     編輯:關於.NET

SOA 與訊息導向架構

Windows Communication Foundation (WCF) 是基於服務導向架構 (SOA) 的分布式技術。在 SOA 系統中,各子系統自治且鬆耦合,透過共享 Contract(而非傳統型別)進行互動。系統間的通訊本質是訊息交換,Client 發送 SOAP Message 呼叫 Service,Service 執行後回傳結果 Message。WCF 提供完整基礎設施處理這一切:從服務呼叫轉換為 Message Exchange、.NET 物件與 XML Infoset 互轉、XML Infoset 與位元組流編碼/解碼、安全性、可靠傳訊、工作階段與交易支援等。

序列化與編碼的區別

序列化是將 .NET 物件結構轉換為 XML 結構的過程,兩者之間需有映射關係,由 Serializer 透過反射分析型別中繼資料實現。編碼則是將 XML Infoset 轉換為網路傳輸的位元組流,WCF 提供 Binary、Text、MTOM 三種編碼方式。序列化屬於 Service Contract 範疇(定義於程式碼),編碼屬於 Binding 範疇(通常於設定檔配置),兩者分離使部署更靈活。

DataContractSerializer 核心映射規則

DataContractSerializer 是 WCF 預設序列化器。類別需標記 [DataContract],成員需標記 [DataMember] 才會被序列化。以下範例定義 DataContractProduct 與 DataContractOrder:

[DataContract]
public class DataContractProduct
{
    [DataMember]
    public Guid ProductID { get; set; }
    [DataMember]
    public string ProductName { get; set; }
    [DataMember]
    private string ProducingArea { get; set; } // private 也可序列化
    [DataMember]
    public double UnitPrice { get; set; }
    // 建構函式省略
}

[DataContract]
[KnownType(typeof(DataContractOrder))]
public class DataContractOrder
{
    [DataMember]
    public Guid OrderID { get; set; }
    [DataMember]
    public DateTime OrderDate { get; set; }
    [DataMember]
    public DataContractProduct Product { get; set; }
    [DataMember]
    public int Quantity { get; set; }
    // 建構函式與 ToString 省略
}

序列化程式碼:

static void SerializeViaDataContractSerializer()
{
    DataContractProduct product = new DataContractProduct(Guid.NewGuid(), "Dell PC", "Xiamen FuJian", 4500);
    DataContractOrder order = new DataContractOrder(Guid.NewGuid(), DateTime.Today, product, 300);
    string fileName = _basePath + "Order.DataContractSerializer.xml";
    using (FileStream fs = new FileStream(fileName, FileMode.Create))
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(DataContractOrder));
        using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs))
        {
            serializer.WriteObject(writer, order);
        }
    }
    Process.Start(fileName);
}

產生的 XML 結構特點:

  • 根元素為型別名稱 DataContractOrder。
  • 型別命名空間自動加入根元素命名空間(https://schemas.datacontract.org/2004/07/Artech.WCFSerialization)。
  • 所有成員以 XML 元素輸出(不支援屬性)。
  • 成員順序依字母排序。
  • 元素名稱即為成員名稱。
  • 不論存取修飾詞,只要標記 [DataMember] 即會序列化(含 private 成員)。
  • 必須標記 [DataContract] 與 [DataMember] 才參與序列化。

透過屬性參數自訂映射

[DataContract] 與 [DataMember] 提供豐富參數調整輸出:

  • Name:指定元素/型別名稱。
  • Namespace:指定命名空間。
  • Order:控制成員輸出順序。
  • IsRequired:對應 XSD minOccurs="1"。
  • EmitDefaultValue:控制預設值是否輸出。

調整後的類別定義:

[DataContract(Name = "product", Namespace = "https://Artech.WCFSerialization/Samples/Product")]
public class DataContractProduct
{
    [DataMember(Name = "id", Order = 1)]
    public Guid ProductID { get; set; }
    [DataMember(Name = "name", Order = 2)]
    public string ProductName { get; set; }
    [DataMember(Name = "producingArea", Order = 3)]
    internal string ProducingArea { get; set; }
    [DataMember(Name = "price", Order = 4)]
    public double UnitPrice { get; set; }
}

[DataContract(Name = "order", Namespace = "https://Artech.WCFSerialization/Samples/Order")]
public class DataContractOrder
{
    [DataMember(Name = "id", Order = 1)]
    public Guid OrderID { get; set; }
    [DataMember(Name = "date", Order = 2)]
    public DateTime OrderDate { get; set; }
    [DataMember(Name = "product", Order = 3)]
    public DataContractProduct Product { get; set; }
    [DataMember(Name = "quantity", Order = 4)]
    public int Quantity { get; set; }
    // KnownType 屬性標記於建構函式上(範例中位置較特殊)
}

序列化後 XML 變為:

<order xmlns="https://Artech.WCFSerialization/Samples/Order" xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
  <id>994b42c4-7767-4ed4-bdf8-033e99c00a64</id>
  <date>2007-03-09T00:00:00+08:00</date>
  <product xmlns:a="https://Artech.WCFSerialization/Samples/Product">
    <a:id>137e6c34-3758-413e-8f8a-83f26f78a174</a:id>
    <a:name>Dell PC</a:name>
    <a:producingArea>Xiamen FuJian</a:producingArea>
    <a:price>4500</a:price>
  </product>
  <quantity>300</quantity>
</order>

KnownType 與舊版 Serializable 支援

序列化時若包含自訂型別(如 DataContractProduct),需在父類別標記 [KnownType] 讓 Serializer 識別。此外,DataContractSerializer 也支援傳統 [Serializable] 屬性標記的型別。

反序列化驗證

反序列化程式碼:

static void DeserializeViaDataContractSerializer()
{
    string fileName = _basePath + "Order.DataContractSerializer.xml";
    DataContractOrder order;
    using (FileStream fs = new FileStream(fileName, FileMode.Open))
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(DataContractOrder));
        using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()))
        {
            order = serializer.ReadObject(reader) as DataContractOrder;
        }
    }
    Console.WriteLine(order);
    Console.Read();
}

執行結果證明反序列化物件與原始物件內容一致,驗證了序列化/反序列化的可逆性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved