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ż