Udostępnij za pośrednictwem


Korzystanie z 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 element DataContractSerializer wywnioskuje kontrakt danych i serializuje wszystkie publicznie widoczne typy. Wszystkie publiczne właściwości odczytu/zapisu i pola typu są serializowane. Możesz wyłączyć członków z serializacji przy użyciu elementu IgnoreDataMemberAttribute. Możesz również jawnie utworzyć kontrakt danych przy użyciu atrybutów DataContractAttribute 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 atrybuty ServiceContractAttribute i OperationContractAttribute zostały jawnie zastosowane. W przykładzie pokazano, że typy pierwotne nie wymagają umowy danych, natomiast 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 na dane dla MyTypes.PurchaseOrder typu poprzez zastosowanie atrybutów DataContractAttribute oraz 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

Notatki

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 z atrybutów DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, EnumMemberAttribute ani nie są oznaczone jako serializowalne za pomocą innych środków (takich jak IXmlSerializable).

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

  • Poziomy dostępności członków (wewnętrzne, prywatne, chronione lub publiczne) nie mają wpływu na kontrakt danych w żadnym stopniu.

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

  • Podczas serializacji kod pobierania właściwości jest wywoływany dla elementów danych właściwości, aby uzyskać wartość właściwości do serializacji.

  • Podczas deserializacji najpierw tworzony jest niezainicjowany obiekt bez wywoływania żadnego konstruktora typu. Następnie wszystkie składowe danych są deserializowane.

  • Podczas deserializacji kod ustawiania właściwości jest wywoływany, aby elementy danych właściwości ustawiały właściwości zgodnie z wartością deserializowaną.

  • Aby kontrakt danych był ważny, musi być możliwe zserializowanie wszystkich jego składników 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

Proponowany typ można serializować niezależnie od tego, czy typ użyty jako parametr 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 także