Używanie kontraktów danych
Kontrakt danych to formalna umowa między usługą a klientem, który abstrakcyjnie opisuje dane do wymiany. Oznacza to, że aby komunikować się, klient i usługa nie muszą współdzielić tych samych typów, tylko tych samych kontraktów danych. Kontrakt danych dokładnie definiuje, dla każdego parametru lub typu zwracanego, jakie dane są serializowane (przekształcone w xml), które mają być wymieniane.
Podstawy kontraktu danych
Program Windows Communication Foundation (WCF) używa aparatu serializacji o nazwie Serializator kontraktu danych domyślnie do serializacji i deserializacji danych (konwertowanie ich na i z xml). Wszystkie typy pierwotne programu .NET Framework, takie jak liczby całkowite i ciągi, a także niektóre typy traktowane jako typy pierwotne, takie jak DateTime i XmlElement, mogą być serializowane bez innych przygotowań i są uważane za domyślne kontrakty danych. Wiele typów programu .NET Framework ma również istniejące kontrakty danych. Aby uzyskać pełną listę typów możliwych do serializacji, zobacz Typy obsługiwane przez serializator kontraktu danych.
Nowe złożone typy tworzone muszą mieć zdefiniowany kontrakt danych, aby można je było serializować. Domyślnie wywnioskuje DataContractSerializer kontrakt danych i serializuje wszystkie publicznie widoczne typy. Wszystkie publiczne właściwości odczytu/zapisu i pola typu są serializowane. Możesz zrezygnować z elementów członkowskich z serializacji przy użyciu elementu IgnoreDataMemberAttribute. Możesz również jawnie utworzyć kontrakt danych przy użyciu DataContractAttribute atrybutów i .DataMemberAttribute Zwykle odbywa się to przez zastosowanie atrybutu DataContractAttribute do typu. Ten atrybut można zastosować do klas, struktur i wyliczeń. Atrybut DataMemberAttribute należy następnie zastosować do każdego elementu członkowskiego typu kontraktu danych, aby wskazać, że jest to element członkowski danych, czyli powinien być serializowany. Aby uzyskać więcej informacji, zobacz Typy możliwe do serializacji.
Przykład
W poniższym przykładzie pokazano kontrakt usługi (interfejs), do którego ServiceContractAttribute zostały jawnie zastosowane atrybuty i OperationContractAttribute . W przykładzie pokazano, że typy pierwotne nie wymagają kontraktu danych, podczas gdy typ złożony.
[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
W poniższym przykładzie pokazano, jak jest tworzony kontrakt danych dla MyTypes.PurchaseOrder
typu przez zastosowanie DataContractAttribute atrybutów i DataMemberAttribute do klasy i jej składowych.
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
Uwagi
Poniższe uwagi zawierają elementy, które należy wziąć pod uwagę podczas tworzenia kontraktów danych:
Atrybut IgnoreDataMemberAttribute jest honorowany tylko wtedy, gdy jest używany z nieoznakowanych typów. Obejmuje to typy, które nie są oznaczone jednym DataContractAttributez atrybutów , SerializableAttribute, CollectionDataContractAttributeEnumMemberAttribute lub oznaczone jako serializowalne za pomocą innych środków (takich jak IXmlSerializable).
Atrybut można zastosować DataMemberAttribute do pól i właściwości.
Poziomy ułatwień dostępu składowych (wewnętrzne, prywatne, chronione lub publiczne) nie mają wpływu na kontrakt danych w żaden sposób.
Atrybut DataMemberAttribute jest ignorowany, jeśli jest stosowany do statycznych elementów członkowskich.
Podczas serializacji kod get właściwości jest wywoływany dla elementów członkowskich danych właściwości, aby uzyskać wartość właściwości do serializacji.
Podczas deserializacji najpierw tworzony jest niezainicjowany obiekt bez wywoływania żadnych konstruktorów w typie. Następnie wszystkie składowe danych są deserializowane.
Podczas deserializacji kod zestawu właściwości jest wywoływany, aby elementy członkowskie danych właściwości ustawiały właściwości na wartość deserializacji.
Aby kontrakt danych był ważny, musi być możliwe serializowanie wszystkich jego elementów członkowskich danych. Aby uzyskać pełną listę typów możliwych do serializacji, zobacz Typy obsługiwane przez serializator kontraktu danych.
Typy ogólne są obsługiwane w dokładnie taki sam sposób, jak typy nieogólne. Nie ma specjalnych wymagań dotyczących parametrów ogólnych. Rozważmy na przykład następujący typ.
[DataContract]
public class MyGenericType1<T>
{
// Code not shown.
}
<DataContract()> _
Public Class MyGenericType1(Of T)
' Code not shown.
End Class
Ten typ można serializować, czy typ używany dla parametru typu ogólnego (T
) jest serializowalny, czy nie. Ponieważ musi być możliwe serializowanie wszystkich elementów członkowskich danych, następujący typ można serializować tylko wtedy, gdy parametr typu ogólnego jest również serializowalny, jak pokazano w poniższym kodzie.
[DataContract]
public class MyGenericType2<T>
{
[DataMember]
T theData;
}
<DataContract()> _
Public Class MyGenericType2(Of T)
<DataMember()> _
Dim theData As T
End Class
Kompletny przykładowy kod usługi WCF definiujący kontrakt danych można znaleźć w przykładzie Podstawowe kontrakty danych.
Zobacz też
- DataMemberAttribute
- DataContractAttribute
- Typy z możliwością serializowania
- Nazwy kontraktów danych
- Równoważność kontraktów danych
- Kolejność elementów członkowskich danych
- Znane typy kontraktów danych
- Kontrakty danych zgodne z nowszymi wersjami
- Przechowywanie wersji kontraktów danych
- Wywołania zwrotne serializacji z tolerancją dla wersji
- Domyślne wartości elementów członkowskich danych
- Typy obsługiwane przez serializator kontraktu danych
- Instrukcje: tworzenie podstawowego kontraktu danych dla klasy lub struktury