Использование контрактов данных

Контракт данных - формальное соглашение между службой и клиентом, абстрактно описывающее данные, обмен которыми происходит. Это значит, что для взаимодействия клиент и служба не обязаны совместно использовать одни и те же типы, достаточно совместно использовать одни и те же контракты данных. Контракт данных для каждого параметра и возвращаемого типа четко определяет, какие данные сериализуются (превращаются в XML) для обмена.

Основные сведения о контрактах данных

Windows Communication Foundation (WCF) использует модуль сериализации, называемый сериализатором контракта данных по умолчанию для сериализации и десериализации данных (преобразование в XML и из него). Все платформа .NET Framework примитивные типы, такие как целые числа и строки, а также определенные типы, которые рассматриваются как примитивы, например DateTime иXmlElement, могут быть сериализованы без другой подготовки и считаются контрактами данных по умолчанию. Многие платформа .NET Framework типы также имеют существующие контракты данных. Полный список сериализуемых типов см. в разделе Types Supported by the Data Contract Serializer.

Для сериализации новых созданных сложных типов необходимо определить контракты данных. По умолчанию DataContractSerializer определяет контракт данных и сериализует все открытые типы. Все открытые свойства чтения/записи и поля типа сериализуются. Можно исключать члены из сериализации с помощью IgnoreDataMemberAttribute. Также можно явно создавать контракт данных с помощью атрибутов DataContractAttribute и DataMemberAttribute . Обычно это делается с помощью применения атрибута DataContractAttribute к типу. Данный атрибут может быть применен к классам, структурам и перечислениям. После этого необходимо применить атрибут DataMemberAttribute к каждому члену типа контракта данных, чтобы указать, что он является членом данных, который необходимо сериализовать. Дополнительные сведения см. в разделе "Сериализуемые типы".

Пример

В следующем примере показано явное применение атрибутов ServiceContractAttribute и OperationContractAttribute к контракту службы (интерфейсу). В нем показано, что типы-примитивы не требуют контрактов данных, в отличие от сложных типов.

[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.PurchaseOrder путем применения атрибутов DataContractAttribute и 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 учитывается только при использовании в неотмеченных типах. Сюда входят типы, которые не отмечены ни одним из атрибутов DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, EnumMemberAttribute или отмечены как сериализуемые любыми другими способами (например, IXmlSerializable).

  • Атрибут DataMemberAttribute применим к полям и свойствам.

  • Уровни доступности членов (внутренний, закрытый, защищенный или открытый) никак не влияют на контракт данных.

  • Атрибут DataMemberAttribute игнорируется, если он применен к статическому члену.

  • Во время сериализации для членов данных свойств вызывается код property-get, возвращающий значения сериализуемых свойств.

  • Во время сериализации вначале создается неинициализированный объект без вызова каких-либо конструкторов типа. Затем десериализуются все члены данных.

  • Во время десериализации для членов данных свойств вызывается код 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 .

См. также