使用数据协定Using Data Contracts

“数据协定” 是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据。A data contract is a formal agreement between a service and a client that abstractly describes the data to be exchanged. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定。That is, to communicate, the client and the service do not have to share the same types, only the same data contracts. 数据协定为每个参数或返回类型精确定义为进行交换而序列化哪些数据(将哪些数据转换为 XML)。A data contract precisely defines, for each parameter or return type, what data is serialized (turned into XML) to be exchanged.

数据协定基本知识Data Contract Basics

默认情况下,Windows Communication Foundation (WCF) 使用一种名为数据协定序列化程序的序列化引擎来序列化和反序列化数据, (将数据与 XML) 相互转换。Windows Communication Foundation (WCF) uses a serialization engine called the Data Contract Serializer by default to serialize and deserialize data (convert it to and from XML). 所有 .NET Framework 基元类型(如整数和字符串)以及某些被视为基元的类型(如 DateTimeXmlElement )都可以进行序列化,而无需进行任何其他准备,并被视为具有默认数据协定。All .NET Framework primitive types, such as integers and strings, as well as certain types treated as primitives, such as DateTime and XmlElement, can be serialized with no other preparation and are considered as having default data contracts. 许多 .NET Framework 类型也具有现有数据协定。Many .NET Framework types also have existing data contracts. 有关可序列化类型的完整列表,请参阅 Types Supported by the Data Contract SerializerFor a full list of serializable types, see Types Supported by the Data Contract Serializer.

必须为所创建的新复杂类型定义数据协定才能序列化这些类型。New complex types that you create must have a data contract defined for them to be serializable. 默认情况下, DataContractSerializer 推断数据协定并序列化所有公共可见类型。By default, the DataContractSerializer infers the data contract and serializes all publicly visible types. 类型的所有公共读/写属性和字段均被序列化。All public read/write properties and fields of the type are serialized. 可以使用 IgnoreDataMemberAttribute从序列化中剔除某些成员。You can opt out members from serialization by using the IgnoreDataMemberAttribute. 还可以使用 DataContractAttributeDataMemberAttribute 属性显式创建数据协定。You can also explicitly create a data contract by using DataContractAttribute and DataMemberAttribute attributes. 正常情况下可通过将 DataContractAttribute 属性应用到该类型来完成该任务。This is normally done by applying the DataContractAttribute attribute to the type. 可以将此属性应用到类、结构和枚举。This attribute can be applied to classes, structures, and enumerations. 然后必须将 DataMemberAttribute 属性应用到数据协定类型的每个成员,以指示这些成员为数据成员, 即应进行序列化。The DataMemberAttribute attribute must then be applied to each member of the data contract type to indicate that it is a data member, that is, it should be serialized. 有关详细信息,请参阅 可序列化类型For more information, see Serializable Types.

示例Example

下面的示例演示已经显式应用了 ServiceContractAttributeOperationContractAttribute 属性的服务协定(接口)。The following example shows a service contract (an interface) to which the ServiceContractAttribute and OperationContractAttribute attributes have been explicitly applied. 该示例演示基元类型不要求数据协定,而复杂类型却对此有要求。The example shows that primitive types do not require a data contract, while a complex type does.

[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 类型的数据协定。The following example shows how a data contract for the MyTypes.PurchaseOrder type is created by applying the DataContractAttribute and DataMemberAttribute attributes to the class and its members.

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

注释Notes

下面的注释提供在创建数据协定时需要考虑的事项:The following notes provide items to consider when creating data contracts:

  • 仅当用于未标记的类型时,才接受 IgnoreDataMemberAttribute 属性。The IgnoreDataMemberAttribute attribute is only honored when used with unmarked types. 这包括未使用 DataContractAttributeSerializableAttributeCollectionDataContractAttributeEnumMemberAttribute 属性之一标记的类型,或通过任何其他方式(如 IXmlSerializable)标记为可序列化的类型。This includes types that are not marked with one of the DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, or EnumMemberAttribute attributes, or marked as serializable by any other means (such as IXmlSerializable).

  • 可以将 DataMemberAttribute 属性 (Attribute) 应用于字段和属性 (Property)。You can apply the DataMemberAttribute attribute to fields, and properties.

  • 成员可访问性级别(internal、private、protected 或 public)对数据协定无任何影响。Member accessibility levels (internal, private, protected, or public) do not affect the data contract in any way.

  • 如果将 DataMemberAttribute 属性应用于静态成员,则将忽略该属性。The DataMemberAttribute attribute is ignored if it is applied to static members.

  • 在序列化期间,为属性数据成员调用 property-get 代码来获取要序列化的属性的值。During serialization, property-get code is called for property data members to get the value of the properties to be serialized.

  • 在反序列化期间,首先创建一个未初始化的对象,而不在该类型上调用任何构造函数。During deserialization, an uninitialized object is first created, without calling any constructors on the type. 然后反序列化所有数据成员。Then all data members are deserialized.

  • 在反序列化期间,为属性数据成员调用 property-set 代码,将属性设置为要反序列化的值。During deserialization, property-set code is called for property data members to set the properties to the value being deserialized.

  • 对于将要生效的数据协定,它必须能序列化其所有数据成员。For a data contract to be valid, it must be possible to serialize all of its data members. 有关可序列化类型的完整列表,请参阅 Types Supported by the Data Contract SerializerFor a full list of serializable types, see Types Supported by the Data Contract Serializer.

    泛型类型的处理方式与非泛型类型完全相同。Generic types are handled in exactly the same way as non-generic types. 泛型参数无特殊要求。There are no special requirements for generic parameters. 例如,请注意以下类型:For example, consider the following type.

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

无论用于泛型类型参数 (T) 的类型能否序列化,此类型都可序列化。This type is serializable whether the type used for the generic type parameter (T) is serializable or not. 因为它必须能序列化所有数据成员,所以下面的类型仅在泛型类型参数也可序列化时才可序列化,如以下代码所示。Because it must be possible to serialize all data members, the following type is serializable only if the generic type parameter is also serializable, as shown in the following code.

[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 示例。For a complete code sample of a WCF service that defines a data contract see the Basic Data Contract sample.

另请参阅See also