Utilización de contratos de datos

Un contrato de datos es un acuerdo formal entre un servicio y un cliente que abstractamente describe los datos que se van a intercambiar. Es decir, para comunicarse, el cliente y el servicio no tienen que compartir los mismos tipos, solo los mismos contratos de datos. Un contrato de datos define con precisión, para cada parámetro o tipo de valor devuelto, qué datos se serializan (se convierten en XML) para su intercambio.

Fundamentos del contrato de datos

Windows Communication Foundation (WCF) utiliza un motor de la serialización llamado Serializador de contrato de datos de forma predeterminada para serializar y deserializar los datos (convertirlos de y a XML). Todos los tipos primitivos de .NET Framework , como enteros y cadenas, así como ciertos tipos tratados como primitivos, como DateTime y XmlElement, se pueden serializar sin otra preparación y se considera que tienen contratos de datos predeterminados. Muchos tipos de .NET Framework también tienen contratos de datos existentes. Para obtener una lista completa de los tipos serializables, consulte Types Supported by the Data Contract Serializer.

Los nuevos tipos complejos que se crean deben tener un contrato de datos definido para que sean serializables. De forma predeterminada, DataContractSerializer deduce el contrato de datos y serializa todos los tipos públicamente visibles. Se serializan todas las propiedades de lectura y escritura públicas y campos del tipo. Puede descartar miembros de la serialización mediante el uso de IgnoreDataMemberAttribute. También puede crear explícitamente un contrato de datos mediante el uso de los atributos DataContractAttribute y DataMemberAttribute . Esto se hace normalmente aplicando el atributo DataContractAttribute al tipo. Este atributo se puede aplicar a clases, estructuras y enumeraciones. El atributo DataMemberAttribute se debe aplicar a continuación a cada miembro del tipo de contrato de datos para indicar que es un miembro de datos, es decir, que se debería serializar. Para obtener más información, consulte Tipos serializables.

Ejemplo

En el ejemplo siguiente se muestra un contrato de servicio (una interfaz) al que se han aplicado los atributos ServiceContractAttribute y OperationContractAttribute explícitamente. El ejemplo muestra que los tipos primitivos no requieren un contrato de datos, mientras un tipo complejo sí lo hace.

[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

El ejemplo siguiente muestra cómo se crea un contrato de datos para el tipo MyTypes.PurchaseOrder aplicando los atributos DataContractAttribute y DataMemberAttribute a la clase y sus miembros.

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

Notas

Las notas siguientes proporcionan los elementos a considerar al crear los contratos de datos:

  • El atributo IgnoreDataMemberAttribute se observa solo cuando se usa con tipos no marcados. Se incluyen los tipos que no están marcados con uno de los atributos DataContractAttribute, SerializableAttribute, CollectionDataContractAttributeo EnumMemberAttribute , o que están marcados como serializables de alguna otra forma (como IXmlSerializable).

  • Puede aplicar el atributo DataMemberAttribute a campos y propiedades.

  • Los niveles (interno, privado, protegido o público) de accesibilidad de miembros no afectan de forma alguna al contrato de datos.

  • Se omite el atributo DataMemberAttribute si se aplica a los miembros estáticos.

  • Durante la serialización, se llama al código de obtención de propiedades para que los miembros de datos de propiedad obtengan el valor de las propiedades a serializar.

  • Durante la deserialización, primero se crea un objeto no inicializado, sin llamar a ningún constructor en el tipo. A continuación, se deserializan todos los miembros de datos.

  • Durante la serialización, se llama al código de conjunto de propiedades para que los miembros de datos de propiedad establezcan el valor de las propiedades que se están deserializando.

  • Para que un contrato de datos sea válido, debe ser posible serializar todos sus miembros de datos. Para obtener una lista completa de los tipos serializables, consulte Types Supported by the Data Contract Serializer.

    Los tipos genéricos se administran exactamente de la misma manera como los tipos no genéricos. No hay ningún requisito especial para los parámetros genéricos. Por ejemplo, veamos el siguiente tipo.

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

Este tipo es serializable tanto si el tipo que se usa para el parámetro de tipo genérico (T) es serializable como si no lo es. Dado que debe ser posible serializar todos los miembros de datos, el tipo siguiente solo es serializable solo si el parámetro de tipo genérico también es serializable, como se muestra en el código siguiente.

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

Para obtener un ejemplo de código completo de un servicio WCF que define un contrato de datos, consulte el ejemplo de Basic Data Contract .

Consulte también