Używanie kontraktów danych

Kontrakt danych to formalna umowa między usługą a klientem, która abstrakcyjnie 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 precyzyjnie definiuje dla każdego parametru lub typu zwracania, jakie dane są serializowane (przekształcone w xml), które mają być wymieniane.

Podstawowe informacje o kontraktach danych

Windows Communication Foundation (WCF) domyślnie używa aparatu serializacji o nazwie serializator kontraktu danych do serializacji i deserializować dane (przekonwertować je na i z XML). Wszystkie .NET Framework typy pierwotne, takie jak liczby całkowite i ciągi, a także niektóre typy traktowane jako typy pierwotne, takie jak i , mogą być serializowane bez innych przygotowań i są uznawane za mające domyślne DateTime XmlElement 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 serializuje je. Domyślnie DataContractSerializer wywnioskuje kontrakt danych i serializuje wszystkie publicznie widoczne typy. Wszystkie publiczne właściwości odczytu/zapisu 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 DataContractAttribute DataMemberAttribute i . Zwykle odbywa się to przez zastosowanie DataContractAttribute atrybutu do typu. Ten atrybut można zastosować do klas, struktur i wyliczeń. Atrybut musi być następnie stosowany do każdego członka typu kontraktu danych, aby wskazać, że jest on członkiem danych, czyli powinien DataMemberAttribute 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 zastosowano atrybuty ServiceContractAttribute OperationContractAttribute 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 dla typu jest tworzony przez zastosowanie atrybutów i do klasy MyTypes.PurchaseOrder DataContractAttribute i jej DataMemberAttribute 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 typami nieoznakowanymi. Obejmuje to typy, które nie są oznaczone za pomocą jednego z atrybutów , , lub albo DataContractAttribute SerializableAttribute oznaczone jako można CollectionDataContractAttribute EnumMemberAttribute serializuje 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 członków (wewnętrzne, prywatne, chronione lub publiczne) nie wpływają w żaden sposób 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, aby uzyskać wartość 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 jest serializowalny, 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

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

Zobacz też