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

WCF 自訂集合完整指南:CollectionDataContract 與 KnownType 實戰

     編輯:關於.NET

為什麼需要自訂集合?

WCF 預設將 List<T>、陣列等標準集合序列化為陣列格式。但當業務需求涉及:

  • 集合本身攜帶額外中繼資料(如總筆數、分頁資訊、查詢耗時)
  • 需要自訂序列化行為(排序、篩選、延遲載入)
  • 跨平台相容性要求特定 XML 結構

此時必須實作自訂集合型別並正確套用資料合約屬性。

實體與集合類別設計

資料實體:Document

[DataContract]
public class Document
{
    [DataMember]
    public string LocalPath { get; set; }

    [DataMember]
    public string FileName { get; set; }

    [DataMember]
    public FileType FileType { get; set; }
}

public enum FileType { TXT, DOC, HTML, OTHER }

自訂集合:DocumentList 實作 IList<Document>


// 關鍵:使用 CollectionDataContract 而非 DataContract
[KnownType(typeof(Document))]
[CollectionDataContract(Name = "DocumentList", ItemName = "Document")]
[Serializable]
public class DocumentList : IList<Document>
{
    private readonly List<Document> _innerList = new List<Document>();

    // 完整實作 IList<Document> 介面方法...
    public int IndexOf(Document item) => _innerList.IndexOf(item);
    public void Insert(int index, Document item) => _innerList.Insert(index, item);
    public void RemoveAt(int index) => _innerList.RemoveAt(index);
    public Document this[int index] { get => _innerList[index]; set => _innerList[index] = value; }
    public void Add(Document item) => _innerList.Add(item);
    public void Clear() => _innerList.Clear();
    public bool Contains(Document item) => _innerList.Contains(item);
    public void CopyTo(Document[] array, int arrayIndex) => _innerList.CopyTo(array, arrayIndex);
    public int Count => _innerList.Count;
    public bool IsReadOnly => _innerList.IsReadOnly;
    public bool Remove(Document item) => _innerList.Remove(item);
    public IEnumerator<Document> GetEnumerator() => _innerList.GetEnumerator();
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => _innerList.GetEnumerator();
}

關鍵屬性深度解析

屬性作用必要性
[CollectionDataContract] 標記為集合資料合約,控制序列化為 XML 元素序列而非陣列 必要
[KnownType(typeof(Document))] 告知序列化器集合項目型別,確保反序列化正確 必要
[Serializable] 支援二進位序列化(如透過 NetTcpBinding) 建議
Name/ItemName 自訂 XML 元素名稱(預設為型別名) 可選

服務合約定義

[ServiceContract]
public interface IDocumentService
{
    [OperationContract]
    [FaultContract(typeof(DirectoryNotFoundException))]
    DocumentList FetchDocuments(string homeDir);
}

常見錯誤與避坑指南

❌ 錯誤:對集合類別套用 [DataContract]

[DataContract] // 錯誤!會導致序列化為物件而非集合
public class DocumentList : IList<Document> { ... }

結果:用戶端收到的集合屬性為 null 或結構錯誤。

❌ 錯誤:缺少 [KnownType]

序列化器無法識別集合項目型別,導致反序列化失敗或項目型別變為 object。

✅ 正確:泛型集合的 Name 屬性技巧

[CollectionDataContract(Name = "DocumentCollection", ItemName = "Doc")]
public class DocumentCollection : List<Document> { }

產生的 XML:<DocumentCollection><Doc>...</Doc></DocumentCollection>

進階:為集合添加業務屬性

[CollectionDataContract]
[KnownType(typeof(Document))]
public class PagedDocumentList : List<Document>
{
    [DataMember]
    public int TotalCount { get; set; }

    [DataMember]
    public int PageIndex { get; set; }

    [DataMember]
    public int PageSize { get; set; }
}

序列化結果同時包含項目清單與分頁中繼資料,極大簡化用戶端邏輯。

總結

WCF 自訂集合的核心在於:實作 IList<T> + 套用 CollectionDataContract + 標註 KnownType。避開 DataContract 陷阱,善用 Name/ItemName 控制 XML 結構,並可擴充業務屬性,讓集合不只是資料容器,更成為豐富的資料傳輸物件(DTO)。

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