Partilhar via


Nomes de contratos de dados

Às vezes, um cliente e um serviço não compartilham os mesmos tipos. Eles ainda podem passar dados uns para os outros, desde que os contratos de dados sejam equivalentes em ambos os lados. A Equivalência de Contrato de Dados é baseada em contratos de dados e nomes de membros de dados e, portanto, um mecanismo é fornecido para mapear tipos e membros para esses nomes. Este tópico explica as regras para nomear contratos de dados, bem como o comportamento padrão da infraestrutura do Windows Communication Foundation (WCF) ao criar nomes.

Regras básicas

As regras básicas relativas aos contratos de atribuição de nomes de dados incluem:

  • Um nome de contrato de dados totalmente qualificado consiste em um namespace e um nome.

  • Os membros de dados têm apenas nomes, mas não namespaces.

  • Ao processar contratos de dados, a infraestrutura WCF diferencia maiúsculas de minúsculas para os namespaces e os nomes de contratos de dados e membros de dados.

Namespaces de contrato de dados

Um namespace de contrato de dados assume a forma de um URI (Uniform Resource Identifier). O URI pode ser absoluto ou relativo. Por padrão, os contratos de dados para um tipo específico recebem um namespace que vem do namespace CLR (Common Language Runtime) desse tipo.

Por padrão, qualquer namespace CLR determinado (no formato Clr.Namespace) é mapeado para o namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. Para substituir esse padrão, aplique o ContractNamespaceAttribute atributo a todo o módulo ou assembly. Como alternativa, para controlar o namespace do contrato de dados para cada tipo, defina a Namespace propriedade do DataContractAttribute.

Nota

O http://schemas.microsoft.com/2003/10/Serialization namespace é reservado e não pode ser usado como um namespace de contrato de dados.

Nota

Não é possível substituir o namespace padrão em tipos de contrato de dados que contenham delegate declarações.

Nomes de contratos de dados

O nome padrão de um contrato de dados para um determinado tipo é o nome desse tipo. Para substituir o padrão, defina a Name propriedade do DataContractAttribute para um nome alternativo. As regras especiais para tipos genéricos são descritas em "Nomes de contratos de dados para tipos genéricos", mais adiante neste tópico.

Nomes de membros de dados

O nome padrão de um membro de dados para um determinado campo ou propriedade é o nome desse campo ou propriedade. Para substituir o padrão, defina a Name propriedade do DataMemberAttribute como um valor alternativo.

Exemplos

O exemplo a seguir mostra como você pode substituir o comportamento de nomenclatura padrão de contratos de dados e membros de dados.

// This overrides the standard namespace mapping for all contracts
// in Contoso.CRM.
[assembly: ContractNamespace("http://schemas.example.com/crm",
   ClrNamespace = "Contoso.CRM")]
namespace Contoso.CRM
{
    // The namespace is overridden to become:
    // http://schemas.example.com/crm.
    // But the name is the default "Customer".
    [DataContract]
    public class Customer
    {
        // Code not shown.
    }
}
namespace Contoso.OrderProc
{
    [DataContract]
    public class PurchaseOrder
    {
        // This data member is named "Amount" by default.
        [DataMember]
        public double Amount;

        // The default is overridden to become "Address".
        [DataMember(Name = "Address")]
        public string Ship_to;
    }
    // The namespace is the default value:
    // http://schemas.datacontract.org/2004/07/Contoso.OrderProc
    // The name is "PurchaseOrder" instead of "MyInvoice".
    [DataContract(Name = "PurchaseOrder")]
    public class MyInvoice
    {
        // Code not shown.
    }

    // The contract name is "Payment" instead of "MyPayment"
    // and the Namespace is "http://schemas.example.com" instead
    // of the default.
    [DataContract(Name = "Payment",
        Namespace = "http://schemas.example.com")]
    public class MyPayment
    {
        // Code not shown.
    }
}
' This overrides the standard namespace mapping for all contracts 
' in Contoso.CRM. 
<Assembly: ContractNamespace("http://schemas.example.com/crm", _
ClrNamespace:="Contoso.CRM")>
Namespace Contoso.CRM
    ' The namespace is overridden to become: 
    ' http://schemas.example.com/crm.
    ' But the name is the default "Customer".
    <DataContract()> _
    Public Class Customer
        ' Code not shown.
    End Class
End Namespace

Namespace Contoso.OrderProc
    <DataContract()> _
    Public Class PurchaseOrder
        ' This data member is named "Amount" by default.
        <DataMember()> _
        Public Amount As Double

        ' The default is overridden to become "Address".
        <DataMember(Name:="Address")> _
        Public Ship_to As String
    End Class

    ' The namespace is the default value:
    ' http://schemas.datacontract.org/2004/07/Contoso.OrderProc
    ' The name is "PurchaseOrder" instead of "MyInvoice".
    <DataContract(Name:="PurchaseOrder")> _
    Public Class MyInvoice
        ' Code not shown.
    End Class

    ' The contract name is "Payment" instead of "MyPayment" 
    ' and the Namespace is "http://schemas.example.com" instead
    ' of the default.
    <DataContract(Name:="Payment", [Namespace]:="http://schemas.example.com")> _
    Public Class MyPayment
        ' Code not shown.
    End Class
End Namespace

Nomes de contratos de dados para tipos genéricos

Existem regras especiais para determinar nomes de contratos de dados para tipos genéricos. Essas regras ajudam a evitar colisões de nomes de contratos de dados entre dois genéricos fechados do mesmo tipo genérico.

Por padrão, o nome do contrato de dados para um tipo genérico é o nome do tipo, seguido pela cadeia de caracteres "Of", seguido pelos nomes de contrato de dados dos parâmetros genéricos, seguido por um hash calculado usando os namespaces de contrato de dados dos parâmetros genéricos. Um hash é o resultado de uma função matemática que atua como uma "impressão digital" que identifica exclusivamente um pedaço de dados. Quando todos os parâmetros genéricos são tipos primitivos, o hash é omitido.

Por exemplo, consulte os tipos no exemplo a seguir.

[DataContract]
public class Drawing<Shape, Brush>
{
    // Code not shown.
}

[DataContract(Namespace = "urn:shapes")]
public class Square
{
    // Code not shown.
}

[DataContract(Name = "RedBrush", Namespace = "urn:default")]
public class RegularRedBrush
{
    // Code not shown.
}

[DataContract(Name = "RedBrush", Namespace = "urn:special")]
public class SpecialRedBrush
{
    // Code not shown.
}
<DataContract()> _
Public Class Drawing(Of Shape, Brush)

    <DataContract([Namespace]:="urn:shapes")> _
    Public Class Square
        ' Code not shown.
    End Class


    <DataContract(Name:="RedBrush", [Namespace]:="urn:default")> _
    Public Class RegularRedBrush
        ' Code not shown.
    End Class

    <DataContract(Name:="RedBrush", [Namespace]:="urn:special")> _
    Public Class SpecialRedBrush
        ' Code not shown.
    End Class
End Class

Neste exemplo, o tipo Drawing<Square,RegularRedBrush> tem o nome do contrato de dados "DrawingOfSquareRedBrush5HWGAU6h", onde "5HWGAU6h" é um hash dos namespaces "urn:shapes" e "urn:default". O tipo Drawing<Square,SpecialRedBrush> tem o nome do contrato de dados "DrawingOfSquareRedBrushjpB5LgQ_S", onde "jpB5LgQ_S" é um hash dos namespaces "urn:shapes" e "urn:special". Observe que, se o hash não for usado, os dois nomes são idênticos e, portanto, ocorre uma colisão de nomes.

Personalizando nomes de contratos de dados para tipos genéricos

Às vezes, os nomes de contratos de dados gerados para tipos genéricos, conforme descrito anteriormente, são inaceitáveis. Por exemplo, você pode saber com antecedência que não encontrará colisões de nomes e talvez queira remover o hash. Nesse caso, você pode usar a DataContractAttribute.Name propriedade para especificar uma maneira diferente de gerar nomes. Você pode usar números em chaves dentro da propriedade para fazer referência a nomes de Name contratos de dados dos parâmetros genéricos. (0 refere-se ao primeiro parâmetro, 1 refere-se ao segundo e assim por diante.) Você pode usar um sinal de número (#) dentro de chaves para se referir ao hash. Você pode usar cada uma dessas referências várias vezes ou não usar de todo.

Por exemplo, o tipo genérico Drawing anterior poderia ter sido declarado como mostrado no exemplo a seguir.

[DataContract(Name = "Drawing_using_{1}_brush_and_{0}_shape")]
public class Drawing<Shape, Brush>
{
    // Code not shown.
}
<DataContract(Name:="Drawing_using_{1}_brush_and_{0}_shape")> _
Public Class Drawing(Of Shape, Brush)
    ' Code not shown.
End Class

Neste caso, o tipo Drawing<Square,RegularRedBrush> tem o nome do contrato de dados "Drawing_using_RedBrush_brush_and_Square_shape". Observe que, como há um "{#}" na Name propriedade, o hash não faz parte do nome e, portanto, o tipo é suscetível a nomear colisões, por exemplo, o tipo Drawing<Square,SpecialRedBrush> teria exatamente o mesmo nome de contrato de dados.

Consulte também