Использование контрактов данных
Контракт данных — формальное соглашение между службой и клиентом, абстрактно описывающее данные, обмен которыми происходит. Это значит, что для взаимодействия клиент и служба не обязаны совместно использовать одни и те же типы, достаточно совместно использовать одни и те же контракты данных. Контракт данных для каждого параметра и возвращаемого типа четко определяет, какие данные сериализуются (превращаются в XML) для обмена.
Основные сведения о контрактах данных
По молчанию в Windows Communication Foundation (WCF) для сериализации и десериализации данных (преобразования в XML и обратно) используется модуль сериализации, называемый сериализатором контракта данных. Все типы-примитивы .NET Framework, такие как integer и string, а также некоторые типы, которые обрабатываются как примитивы, такие как DateTime и XmlElement, могут быть сериализованы без дополнительной обработки и считаются типами, которые по умолчанию содержат контракты данных. Многие типы .NET Framework также содержат контракты данных. Полный список сериализуемых типов см. в разделе Типы, поддерживаемые сериализатором контракта данных.
Для сериализации новых созданных сложных типов необходимо определить контракты данных. По умолчанию DataContractSerializer определяет контракт данных и сериализует все открытые типы. Все открытые свойства чтения/записи и поля типа сериализуются. Можно исключать члены из сериализации с помощью IgnoreDataMemberAttribute. Также можно явно создавать контракт данных с помощью атрибутов DataContractAttribute и DataMemberAttribute. Обычно это делается с помощью применения атрибута DataContractAttribute к типу. Данный атрибут может быть применен к классам, структурам и перечислениям. После этого необходимо применить атрибут DataMemberAttribute к каждому члену типа контракта данных, чтобы указать, что он является членом данных, который необходимо сериализовать. Дополнительные сведения см. в разделе Сериализуемые типы.
Пример
В следующем примере показано явное применение атрибутов ServiceContractAttribute и OperationContractAttribute к контракту службы (интерфейсу). В нем показано, что типы-примитивы не требуют контрактов данных, в отличие от сложных типов.
<ServiceContract()> _
Public Interface ISampleInterface
' No data contract is requred 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
[ServiceContract]
public interface ISampleInterface
{
// No data contract is requred 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);
}
В следующем примере показано создание контракта данных для типа MyTypes.PurchaseOrder
путем применения атрибутов DataContractAttribute и DataMemberAttribute к классу и его членам.
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
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; }
}
}
}
Примечания
Существуют некоторые моменты, которые необходимо учитывать при создании контрактов данных:
Атрибут IgnoreDataMemberAttribute учитывается только при использовании в неотмеченных типах. Сюда входят типы, которые не отмечены ни одним из атрибутов DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, EnumMemberAttribute или отмечены как сериализуемые любыми другими способами (например, IXmlSerializable).
Атрибут DataMemberAttribute применим к полям и свойствам.
Уровни специальных возможностей членов (внутренний, закрытый, защищенный или открытый) никак не влияют на контракт данных.
Атрибут DataMemberAttribute игнорируется, если он применен к статическому члену.
Во время сериализации для членов данных свойств вызывается код property-get, возвращающий значения сериализуемых свойств.
Во время сериализации вначале создается неинициализированный объект без вызова каких-либо конструкторов типа. Затем десериализуются все члены данных.
Во время десериализации для членов данных свойств вызывается код property-set, задающий значения сериализуемым свойствам.
Чтобы контракт данных был допустимым, все его члены данных должны быть сериализуемыми. Полный список сериализуемых типов см. в разделе Типы, поддерживаемые сериализатором контракта данных.
Универсальные типы обрабатываются таким же образом, как и неуниверсальные. Для универсальных параметров нет особых требований. Например, рассмотрим следующий тип:
<DataContract()> _
Public Class MyGenericType1 (Of T)
' Code not shown.
End Class
[DataContract]
public class MyGenericType1<T>
{
// Code not shown.
}
Этот тип является сериализуемым независимо от того, используется ли для параметра универсального типа (T) сериализуемый тип или нет. Поскольку все члены данных должны быть сериализуемыми, следующий тип является сериализуемым, только если параметр универсального типа также является сериализуемым, как показано в следующем коде.
<DataContract()> Public Class MyGenericType2(Of T)
<DataMember()> Dim theData As T
End Class
[DataContract]
public class MyGenericType2<T>
{
[DataMember]
T theData;
}
См. также
Задачи
Как создать базовый контракт данных для класса или структуры
Справочник
DataMemberAttribute
DataContractAttribute
Основные понятия
Сериализуемые типы
Имена контрактов данных
Эквивалентность контрактов данных
Порядок элементов данных
Известные типы контрактов данных
Контракты данных, совместимые с любыми будущими изменениями
Управление версиями контракта данных
Обратные вызовы сериализации, независимые от версий
Значения элементов данных по умолчанию
Типы, поддерживаемые сериализатором контракта данных