Uso di contratti di dati

Un contratto dati è un accordo formale tra un servizio e un client che descrive astrattamente i dati da scambiare. Per comunicare, non è necessario che il client e il servizio condividano gli stessi tipi, ma solo gli stessi contratti dati. Un contratto dati definisce con precisione, per ogni parametro o tipo restituito, i dati serializzati (trasformati in XML) che verranno scambiati.

Nozioni fondamentali dei contratti dati

Per impostazione predefinita in Windows Communication Foundation (WCF) viene utilizzato un motore di serializzazione denominato serializzatore dei contratti dati per serializzare e deserializzare i dati (convertendoli in/da XML). Ogni tipo primitivo .NET Framework, ad esempio numeri interi e stringhe, nonché alcuni tipi trattati come primitivi, ad esempio DateTime e XmlElement, può essere serializzato senza ulteriore preparazione ed è considerato in possesso di contratti dati predefiniti. Molti tipi .NET Framework, inoltre, dispongono di contratti dati esistenti. Per un elenco completo dei tipi serializzabili, vedere Types Supported by the Data Contract Serializer.

Per poter essere serializzabili, è necessario che i nuovi tipi complessi creati dispongano di un contratto dati appositamente definito. Per impostazione predefinita, tramite DataContractSerializer viene dedotto il contratto dati e vengono serializzati tutti i tipi visibili pubblicamente. Vengono serializzati i campi e le proprietà di lettura/scrittura pubblici del tipo. È possibile rifiutare esplicitamente i membri per la serializzazione tramite IgnoreDataMemberAttribute. È inoltre possibile creare in modo esplicito un contratto dati utilizzando gli attributi DataContractAttribute e DataMemberAttribute . Ciò viene di norma realizzato applicando l'attributo DataContractAttribute al tipo. Questo attributo può essere applicato a classi, strutture ed enumerazioni. L'attributo DataMemberAttribute deve quindi essere applicato a ogni membro del tipo di contratto dati per indicare che si tratta di un membro dati, ovvero che deve essere serializzato. Per altre informazioni, vedere Tipi serializzabili.

Esempio

Nell'esempio seguente viene illustrato un contratto di servizio (un'interfaccia) a cui sono stati applicati in modo esplicito gli attributi ServiceContractAttribute e OperationContractAttribute . Nell'esempio viene mostrato che i tipi primitivi non richiedono un contratto dati, diversamente da un tipo complesso.

[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

Nell'esempio seguente viene illustrato come creare un contratto dati per il tipo MyTypes.PurchaseOrder creato applicando gli attributi DataContractAttribute e DataMemberAttribute alla classe e ai relativi membri.

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

Note

Nelle note seguenti sono contenuti gli elementi da tenere presenti durante la creazione di contratti dati:

  • L'attributo IgnoreDataMemberAttribute viene accettato solo se utilizzato con tipi non contrassegnati. Sono inclusi i tipi non contrassegnati con uno degli attributi DataContractAttribute, SerializableAttribute, CollectionDataContractAttributeo EnumMemberAttribute oppure contrassegnati come serializzabili in qualsiasi altro modo (ad esempio IXmlSerializable).

  • È possibile applicare l'attributo DataMemberAttribute a campi e proprietà.

  • I livelli di accessibilità ai membri (interno, privato, protetto o pubblico) non influiscono in alcun modo sul contratto dati.

  • L'attributo DataMemberAttribute viene ignorato se applicato a membri statici.

  • Durante la serializzazione il codice della proprietà get viene chiamato per i membri dati della proprietà per ottenere il valore delle proprietà da serializzare.

  • Durante la deserializzazione viene prima creato un oggetto non inizializzato, senza chiamare alcun costruttore per il tipo, quindi vengono deserializzati tutti i membri dati.

  • Durante la deserializzazione il codice della proprietà set viene chiamato per i membri dati della proprietà per impostare le proprietà sul valore in fase di deserializzazione.

  • Perché un contratto dati sia valido, deve essere possibile serializzare tutti i relativi membri dati. Per un elenco completo dei tipi serializzabili, vedere Types Supported by the Data Contract Serializer.

    I tipi generici sono gestiti esattamente nello stesso modo dei tipi non generici. Non vi sono requisiti speciali per i parametri generici. Si consideri ad esempio il tipo seguente:

[DataContract]
public class MyGenericType1<T>
{
    // Code not shown.
}
<DataContract()> _
Public Class MyGenericType1(Of T)
    ' Code not shown.
End Class

Il tipo è serializzabile indipendentemente dal fatto che il tipo utilizzato per il parametro di tipo generico (T) sia serializzabile o meno. Poiché deve essere possibile serializzare tutti i membri dati, il tipo seguente è serializzabile solo se il parametro di tipo generico è anch'esso serializzabile, come indicato nel codice seguente.

[DataContract]
public class MyGenericType2<T>
{
    [DataMember]
    T theData;
}
<DataContract()> _
Public Class MyGenericType2(Of T)
    <DataMember()> _
    Dim theData As T
End Class

Per un esempio di codice completo di un servizio WCF che definisce un contratto dati, vedere l'esempio Basic Data Contract .

Vedi anche