Поделиться через


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

Контракт данных — это официальное соглашение между службой и клиентом, которое абстрактно описывает обмен данными. То есть для взаимодействия клиент и служба не обязаны использовать одни и те же типы, только одни и те же контракты данных. Контракт данных точно определяет для каждого параметра или возвращаемого типа, какие данные преобразованы в XML для обмена.

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

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

Новые сложные типы, создаваемые, должны иметь контракт данных, определенный для их сериализации. По умолчанию 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 игнорируется, если он применяется к статическим элементам.

  • Во время сериализации код получения свойств вызывается для членов данных свойств, чтобы получить значение этих свойств для сериализации.

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

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

  • Чтобы контракт данных был действительным, необходимо сериализовать все его члены. Полный список сериализуемых типов см. в разделе "Типы", поддерживаемые сериализатором контракта данных.

    Универсальные типы обрабатываются точно так же, как и не универсальные типы. Для универсальных параметров нет особых требований. Например, рассмотрим следующий тип.

[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, определяющей контракт данных, см. в примере "Базовый контракт данных ".

См. также