Używanie kontraktów danych

Kontrakt danych to formalna umowa między usługą a klientem, która w sposób abstrakcyjny opisuje dane do wymiany. Oznacza to, że aby się komunikować, klient i usługa nie muszą współużytkować tych samych typów, tylko tych samych kontraktów danych. Kontrakt danych dokładnie definiuje dla każdego parametru lub zwracany typ, jakie dane są serializowane (przekształcone w XML), które mają być wymieniane.

Podstawowe informacje o kontraktach danych

Windows Communication Foundation (WCF) używa aparatu serializacji o nazwie serializator kontraktu danych domyślnie do serializacji i deserializować dane (konwertowanie ich do i z xml). Wszystkie .NET Framework pierwotne, takie jak liczby całkowite i ciągi, a także niektóre typy traktowane jako typy pierwotne, DateTimeXmlElementtakie jak i , mogą być serializowane bez innych przygotowań i są uznawane za mające domyślne kontrakty danych. Wiele .NET Framework ma również istniejące kontrakty danych. Aby uzyskać pełną listę typów, które można serializuje, zobacz Typy obsługiwane przez serializator kontraktu danych.

Nowe typy złożone, które tworzysz, muszą mieć zdefiniowany kontrakt danych, aby można było je serializuje. Domyślnie wywnioskuje DataContractSerializer kontrakt danych i serializuje wszystkie publicznie widoczne typy. Wszystkie właściwości publicznych odczyt/zapis i pola typu są serializowane. Można zrezygnować z serializacji elementów członkowskich przy użyciu IgnoreDataMemberAttribute. Możesz również jawnie utworzyć kontrakt danych przy użyciu atrybutów DataContractAttributeDataMemberAttribute i . Zwykle odbywa się to przez zastosowanie atrybutu DataContractAttribute do typu. Ten atrybut można zastosować do klas, struktur i wyliczeń. Atrybut DataMemberAttribute musi być następnie stosowany do każdego członka typu kontraktu danych, aby wskazać DataMemberAttribute jest on członkiem danych, to oznacza, że powinien być serializowany. Aby uzyskać więcej informacji, zobacz Serializable Types (Typy, które można serializuje).

Przykład

W poniższym przykładzie pokazano kontrakt usługi (interfejs), do którego jawnie ServiceContractAttributeOperationContractAttribute zastosowano atrybuty i . W przykładzie pokazano, że typy pierwotne nie wymagają kontraktu danych, podczas gdy typ złożony ma wartość .

[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 kontrakt danych MyTypes.PurchaseOrder dla typu jest tworzony 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 stosowany tylko wtedy, gdy jest używany z typami nieoznakowanymi. Obejmuje to typy, które nie są oznaczone DataContractAttributeza pomocą jednego z atrybutów , SerializableAttribute, CollectionDataContractAttributelub EnumMemberAttribute albo oznaczone jako można serializuje za pomocą innych środków (takich jak IXmlSerializable).

  • Atrybut można zastosować do DataMemberAttribute pól i właściwości.

  • Poziomy ułatwień dostępu członków (wewnętrzne, prywatne, chronione lub publiczne) w żaden sposób nie wpływają na kontrakt danych.

  • Atrybut DataMemberAttribute jest ignorowany, jeśli jest stosowany do statycznych elementów członkowskich.

  • Podczas serializacji kod property-get jest wywoływany dla elementów członkowskich danych właściwości w celu uzyskania wartości właściwości do serializacji.

  • Podczas deserializacji niezainicjowany obiekt jest tworzony po raz pierwszy, bez wywoływania jakichkolwiek konstruktorów w typie. Następnie wszystkie elementy członkowskie danych są deserializowane.

  • Podczas deserializacji kod zestawu właściwości jest wywoływany dla elementów członkowskich danych właściwości, aby ustawić właściwości na wartość deserializacji.

  • Aby kontrakt danych był prawidłowy, musi być możliwe serializowanie wszystkich jego elementów członkowskich danych. Aby uzyskać pełną listę typów, które można serializuje, zobacz Typy obsługiwane przez serializator kontraktu danych.

    Typy ogólne są obsługiwane w dokładnie taki sam sposób jak typy niegeneryczne. Nie ma żadnych 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 serializuje, czy typ używany dla parametru typu ogólnego (T) jest serializowalny, czy nie. Ponieważ musi być możliwe do serializacji wszystkich elementów członkowskich danych, następujący typ jest serializowalny tylko wtedy, gdy parametr typu ogólnego jest również możliwe do serializacji, 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

Pełny przykład kodu usługi WCF definiującej kontrakt danych zawiera przykładowy podstawowy kontrakt danych.

Zobacz też