Usando contratos de dados

Um contrato de dados é um acordo formal entre um serviço e um cliente que descreve abstratamente os dados a serem trocados. Ou seja, para comunicar, o cliente e o serviço não precisam compartilhar os mesmos tipos, apenas os mesmos contratos de dados. Um contrato de dados define com precisão, para cada parâmetro ou tipo de retorno, quais dados são serializados (transformados em XML) a serem trocados.

Noções básicas sobre contratos de dados

O Windows Communication Foundation (WCF) usa um mecanismo de serialização chamado Data Contract Serializer por padrão para serializar e desserializar dados (convertê-los para e de XML). Todos os tipos primitivos do .NET Framework, como inteiros e cadeias de caracteres, bem como certos tipos tratados como primitivos, como DateTime e XmlElement, podem ser serializados sem outra preparação e são considerados como tendo contratos de dados padrão. Muitos tipos do .NET Framework também têm contratos de dados existentes. Para obter uma lista completa de tipos serializáveis, consulte Tipos suportados pelo Data Contract Serializer.

Novos tipos complexos criados devem ter um contrato de dados definido para que sejam serializáveis. Por padrão, o DataContractSerializer infere o contrato de dados e serializa todos os tipos publicamente visíveis. Todas as propriedades públicas de leitura/gravação e campos do tipo são serializados. Você pode excluir membros da serialização usando o IgnoreDataMemberAttribute. Você também pode criar explicitamente um contrato de dados usando DataContractAttribute e DataMemberAttribute atributos. Isso geralmente é feito aplicando o DataContractAttribute atributo ao tipo. Esse atributo pode ser aplicado a classes, estruturas e enumerações. O DataMemberAttribute atributo deve então ser aplicado a cada membro do tipo de contrato de dados para indicar que é um membro de dados, ou seja, deve ser serializado. Para obter mais informações, consulte Tipos serializáveis.

Exemplo

O exemplo a seguir mostra um contrato de serviço (uma interface) ao qual os ServiceContractAttribute atributos e OperationContractAttribute foram explicitamente aplicados. O exemplo mostra que os tipos primitivos não exigem um contrato de dados, enquanto um tipo complexo exige.

[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

O exemplo a seguir mostra como um contrato de dados para o MyTypes.PurchaseOrder tipo é criado aplicando os DataContractAttribute atributos e DataMemberAttribute à classe e seus membros.

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

As notas a seguir fornecem itens a serem considerados ao criar contratos de dados:

  • O IgnoreDataMemberAttribute atributo só é honrado quando usado com tipos não marcados. Isso inclui tipos que não são marcados com um dos atributos , , , ou EnumMemberAttribute marcados DataContractAttributecomo serializáveis por qualquer outro meio (como IXmlSerializable). CollectionDataContractAttributeSerializableAttribute

  • Você pode aplicar o DataMemberAttribute atributo a campos e propriedades.

  • Os níveis de acessibilidade do membro (interno, privado, protegido ou público) não afetam o contrato de dados de forma alguma.

  • O DataMemberAttribute atributo será ignorado se for aplicado a membros estáticos.

  • Durante a serialização, o código property-get é chamado para que os membros de dados de propriedade obtenham o valor das propriedades a serem serializadas.

  • Durante a desserialização, um objeto não inicializado é criado primeiro, sem chamar nenhum construtor no tipo. Em seguida, todos os membros de dados são desserializados.

  • Durante a desserialização, o código do conjunto de propriedades é chamado para que os membros de dados de propriedade definam as propriedades para o valor que está sendo desserializado.

  • Para que um contrato de dados seja válido, deve ser possível serializar todos os seus membros de dados. Para obter uma lista completa de tipos serializáveis, consulte Tipos suportados pelo Data Contract Serializer.

    Os tipos genéricos são tratados exatamente da mesma forma que os tipos não genéricos. Não existem requisitos especiais para parâmetros genéricos. Por exemplo, considere o seguinte tipo.

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

Esse tipo é serializável se o tipo usado para o parâmetro de tipo genérico (T) é serializável ou não. Como deve ser possível serializar todos os membros de dados, o tipo a seguir é serializável somente se o parâmetro de tipo genérico também for serializável, conforme mostrado no código a seguir.

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

Para obter um exemplo de código completo de um serviço WCF que define um contrato de dados, consulte o Exemplo de contrato de dados básico.

Consulte também