Nomi di contratto dati

Talvolta un client e un servizio non condividono gli stessi tipi. Possono comunque passarsi dati a condizione che i contratti dati siano equivalenti su entrambi i lati. L'equivalenza del contratto di dati è basata sui nomi dei contratti dati e dei membri dati e pertanto viene fornito un meccanismo per eseguire il mapping di tipi e membri a quei nomi. In questo argomento vengono illustrate le regole per denominare i contratti dati, nonché il comportamento predefinito dell'infrastruttura WCF (Windows Communication Foundation) quando si creano nomi.

Regole di base

Le regole di base sulla denominazione di contratti dati sono le seguenti:

  • Un nome di contratto dati completo è costituito da uno spazio dei nomi e da un nome.

  • I membri dati hanno solo nomi, ma non spazi dei nomi.

  • Nell'elaborazione di contratti dati, l'infrastruttura WCF applica la distinzione tra maiuscole e minuscole sia agli spazi dei nomi che ai nomi di contratto dati e di membro dati.

Spazi dei nomi di contratto dati

Uno spazio dei nomi di contratto dati prende il formato di un URI (Uniform Resource Identifier). L'URI può essere assoluto o relativo. Per impostazione predefinita, ai contratti dati per un particolare tipo viene assegnato uno spazio dei nomi che proviene dallo spazio dei nomi CLR (Common Language Runtime) di quel tipo.

Per impostazione predefinita, qualsiasi spazio dei nomi CLR specificato (nel formato Clr.Namespace) viene mappato allo spazio dei nomi http://schemas.datacontract.org/2004/07/Clr.Namespace. Per eseguire l'override di questa impostazione predefinita, applicare l'attributo ContractNamespaceAttribute all'intero modulo o assembly. In alternativa, per controllare lo spazio dei nomi di contratto dati per ogni tipo, impostare la proprietà Namespace di DataContractAttribute.

Nota

Lo spazio dei nomi http://schemas.microsoft.com/2003/10/Serialization è riservato e non può essere usato come spazio dei nomi del contratto dati.

Nota

Non è possibile eseguire l'override dello spazio dei nomi predefinito nei tipi di contratto dati che contengono dichiarazioni delegate.

Nomi di contratto dati

Il nome predefinito di un contratto dati per un determinato tipo è il nome di quel tipo. Per eseguire l'override dell'impostazione predefinita, impostare la proprietà Name di DataContractAttribute su un nome alternativo. Le regole speciali per i tipi generici vengono descritte in "Nomi di contratto dati per tipi generici" più avanti in questo argomento.

Nomi di membro dati

Il nome predefinito di un membro dati per un campo o una proprietà specifici è il nome di quel campo o di quella proprietà. Per eseguire l'override dell'impostazione predefinita, impostare la proprietà Name di DataMemberAttribute su un valore alternativo.

Esempi

Negli esempi seguenti viene illustrato come eseguire l'override del comportamento di denominazione predefinito dei contratti dati e dei membri dati.

// 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

Nomi di contratto dati per tipi generici

Per determinare i nomi di contratto dati per tipi generici, esistono regole speciali. Le regole consentono di evitare collisioni dei nomi di contratto dati tra due generics chiusi dello stesso tipo generico.

Per impostazione predefinita, il nome di contratto dati per un tipo generico è il nome del tipo, seguito dalla stringa "Of", seguita dai nomi di contratto dati dei parametri generici, seguiti da un hash calcolato usando gli spazi dei nomi di contratto dati dei parametri generici. Un hash è il risultato di una funzione matematica che funge da "impronta digitale" che identifica in modo univoco un blocco di dati. Quando tutti i parametri generici sono tipi primitivi, l'hash viene omesso.

Vedere, ad esempio, i tipi nell'esempio seguente:

[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

In questo esempio, il tipo Drawing<Square,RegularRedBrush> ha il nome di contratto dati "DrawingOfSquareRedBrush5HWGAU6h", dove "5HWGAU6h" è un hash degli spazi dei nomi "urn:shapes" e "urn:default". Il tipo Drawing<Square,SpecialRedBrush> ha il nome di contratto dati "DrawingOfSquareRedBrushjpB5LgQ_S", dove "jpB5LgQ_S" è un hash degli spazi dei nomi "urn:shapes" e "urn:special". Si noti che se non viene utilizzato l'hash, i due nomi sarebbero identici e si verificherebbe una collisione.

Personalizzazione dei nomi dei contratti dati per i tipi generici

I nomi di contratto dati generati per i tipi generici, come descritto prima, talvolta sono inaccettabili. Si potrebbe ad esempio sapere in anticipo che non si verificheranno collisioni di nomi e si potrebbe volere rimuovere l'hash. In questo caso, è possibile usare la proprietà DataContractAttribute.Name per specificare un modo diverso per generare i nomi. È possibile utilizzare numeri tra parentesi graffe all'interno della proprietà Name per fare riferimento a nomi di contratto dati dei parametri generici. 0 fa riferimento al primo parametro, 1 fa riferimento al secondo e così via. È possibile usare un simbolo cancelletto (#) tra parentesi graffe per fare riferimento all'hash. È possibile utilizzare ogni riferimento più volte o non utilizzarlo affatto.

Ad esempio, il tipo Drawing generico precedente avrebbe potuto essere dichiarato come illustrato nell'esempio seguente.

[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

In questo caso, il tipo Drawing<Square,RegularRedBrush> ha il nome di contratto dati "Drawing_using_RedBrush_brush_and_Square_shape". Si noti che, poiché nella proprietà Name è presente un segno "{#}", l'hash non è parte del nome, pertanto il tipo è esposto a collisioni di nomi. Il tipo Drawing<Square,SpecialRedBrush>, ad esempio, avrebbe esattamente lo stesso nome di contratto dati.

Vedi anche