使用資料合約

資料合約 」(Data Contract) 是服務與用戶端之間的正式合約,其中會抽象地描述要交換的資料。 也就是說,若要進行通訊,用戶端與服務並不需要共用相同的型別,而只需要共用相同的資料合約。 資料合約會針對每個參數或傳回型別精確地定義哪些資料要序列化 (變成 XML) 才能進行交換。

資料合約基本概念

根據預設,Windows Communication Foundation (WCF) 會使用稱為「資料合約序列化程式」的序列化引擎來序列化和還原序列化資料 (在資料和 XML 之間來回轉換)。 包括像是整數和字串的所有 .NET Framework 基本型別 (Primitive Type),以及被視為基本型別的特定型別,例如 DateTimeXmlElement,都可以不用經過其他準備即加以序列化,而且會被視為具有預設的資料合約。 許多 .NET Framework 型別也具有現有的資料合約。 如需可序列化型別的完整清單,請參閱 Types Supported by the Data Contract Serializer

您建立的新複雜型別必須具有已針對其所定義的資料合約,才能夠進行序列化。 根據預設, DataContractSerializer 會推斷資料合約,並且會序列化所有公開可見的型別。 型別的所有公用讀取/寫入屬性 (Property) 和欄位都會序列化。 您可以藉由使用 IgnoreDataMemberAttribute,選擇不序列化成員。 您也可以使用 DataContractAttributeDataMemberAttribute 屬性 (Attribute) 明確建立資料合約。 通常將 DataContractAttribute 屬性套用至該型別即可達成這點。 這個屬性可以套用至類別、結構和列舉型別 (Enumeration)。 然後, DataMemberAttribute 屬性必須套用至資料合約型別的各個成員,以表示其為「 資料成員」(Data Member),也就是這個成員應該要加以序列化。 如需詳細資訊,請參閱可序列化型別

範例

下列範例會示範已經明確套用 ServiceContractAttributeOperationContractAttribute 屬性的服務合約 (介面)。 此範例會示範基本型別不需要資料合約,而複雜型別則需要。

[ServiceContract]
public interface ISampleInterface
{
    // No data contract is required since both the parameter
    // and return types are primitive types.
    [OperationContract]
    double SquareRoot(int root);

    // No Data Contract required because both parameter and return
    // types are marked with the SerializableAttribute attribute.
    [OperationContract]
    System.Drawing.Bitmap GetPicture(System.Uri pictureUri);

    // The MyTypes.PurchaseOrder is a complex type, and thus
    // requires a data contract.
    [OperationContract]
    bool ApprovePurchaseOrder(MyTypes.PurchaseOrder po);
}
<ServiceContract()> _
Public Interface ISampleInterface
    ' No data contract is required since both the parameter and return 
    ' types are both primitive types.
    <OperationContract()> _
    Function SquareRoot(ByVal root As Integer) As Double

    ' No Data Contract required because both parameter and return 
    ' types are marked with the SerializableAttribute attribute.
    <OperationContract()> _
    Function GetPicture(ByVal pictureUri As System.Uri) As System.Drawing.Bitmap

    ' The MyTypes.PurchaseOrder is a complex type, and thus 
    ' requires a data contract.
    <OperationContract()> _
    Function ApprovePurchaseOrder(ByVal po As MyTypes.PurchaseOrder) As Boolean
End Interface

下列範例會示範如何透過將 MyTypes.PurchaseOrderDataContractAttribute 屬性套用至類別及其成員,以便建立 DataMemberAttribute 型別的資料合約。

namespace MyTypes
{
    [DataContract]
    public class PurchaseOrder
    {
        private int poId_value;

        // Apply the DataMemberAttribute to the property.
        [DataMember]
        public int PurchaseOrderId
        {

            get { return poId_value; }
            set { poId_value = value; }
        }
    }
}
Namespace MyTypes
    <System.Runtime.Serialization.DataContractAttribute()> _
    Public Class PurchaseOrder
        Private poId_value As Integer

        ' Apply the DataMemberAttribute to the property.

        <DataMember()> _
        Public Property PurchaseOrderId() As Integer

            Get
                Return poId_value
            End Get
            Set
                poId_value = value
            End Set
        End Property
    End Class
End Namespace

備註

下列注意事項提供在建立資料合約時的考慮項目:

  • IgnoreDataMemberAttribute 屬性只有在搭配未標記的型別使用時才會被接受。 其中包含未使用 DataContractAttributeSerializableAttributeCollectionDataContractAttributeEnumMemberAttribute 屬性其中一個所標記的型別,或未透過任何其他方式 (例如 IXmlSerializable) 標記為可序列化的型別。

  • 您可以將 DataMemberAttribute 屬性 (Attribute) 套用至欄位和屬性 (Property)。

  • 成員存取層級 (內部、私密、保護或公用) 不會以任何形式影響資料合約。

  • DataMemberAttribute 屬性在套用至靜態成員時會遭到忽略。

  • 取得屬性 (property-get) 的程式碼會在進行序列化時呼叫,以便讓屬性資料成員取得要進行序列化之屬性的值。

  • 在進行還原序列化時會先建立未初始化的物件,而不會呼叫該型別上的任何建構函式 (Constructor)。 接下來,所有的資料成員都會還原序列化。

  • 設定屬性 (property-set) 的程式碼會在進行還原序列化時呼叫,以便讓屬性資料成員設定要進行還原序列化之屬性的值。

  • 若是有效的資料合約,該資料合約肯定是可能會序列化其所有資料成員。 如需可序列化型別的完整清單,請參閱 Types Supported by the Data Contract Serializer

    對於泛型型別的處理方式與非泛型型別完全相同。 對於泛型參數沒有特殊的需求。 以下列型別為例:

[DataContract]
public class MyGenericType1<T>
{
    // Code not shown.
}
<DataContract()> _
Public Class MyGenericType1(Of T)
    ' Code not shown.
End Class

無論用於泛型型別參數 (T) 的型別是否為可序列化的型別,這個型別都是可序列化的型別。 由於其一定可以序列化所有的資料成員,所以下列型別只有在泛型型別參數也屬於可序列化時才能進行序列化,如下列程式碼所示。

[DataContract]
public class MyGenericType2<T>
{
    [DataMember]
    T theData;
}
<DataContract()> _
Public Class MyGenericType2(Of T)
    <DataMember()> _
    Dim theData As T
End Class

如需定義資料合約的 WCF 服務完整程式碼範例,請參閱 Basic Data Contract 範例。

另請參閱