Редактиране

Споделяне чрез


Data Contract Names

Sometimes a client and a service do not share the same types. They can still pass data to each other as long as the data contracts are equivalent on both sides. Data Contract Equivalence is based on data contract and data member names, and therefore a mechanism is provided to map types and members to those names. This topic explains the rules for naming data contracts as well as the default behavior of the Windows Communication Foundation (WCF) infrastructure when creating names.

Basic Rules

Basic rules regarding naming data contracts include:

  • A fully-qualified data contract name consists of a namespace and a name.

  • Data members have only names, but no namespaces.

  • When processing data contracts, the WCF infrastructure is case-sensitive to both the namespaces and the names of data contracts and data members.

Data Contract Namespaces

A data contract namespace takes the form of a Uniform Resource Identifier (URI). The URI can be either absolute or relative. By default, data contracts for a particular type are assigned a namespace that comes from the common language runtime (CLR) namespace of that type.

By default, any given CLR namespace (in the format Clr.Namespace) is mapped to the namespace http://schemas.datacontract.org/2004/07/Clr.Namespace. To override this default, apply the ContractNamespaceAttribute attribute to the entire module or assembly. Alternatively, to control the data contract namespace for each type, set the Namespace property of the DataContractAttribute.

Note

The http://schemas.microsoft.com/2003/10/Serialization namespace is reserved and cannot be used as a data contract namespace.

Note

You cannot override the default namespace in data contract types that contain delegate declarations.

Data Contract Names

The default name of a data contract for a given type is the name of that type. To override the default, set the Name property of the DataContractAttribute to an alternative name. Special rules for generic types are described in "Data Contract Names for Generic Types" later in this topic.

Data Member Names

The default name of a data member for a given field or property is the name of that field or property. To override the default, set the Name property of the DataMemberAttribute to an alternative value.

Examples

The following example shows how you can override the default naming behavior of data contracts and data members.

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

Data Contract Names for Generic Types

Special rules exist for determining data contract names for generic types. These rules help avoid data contract name collisions between two closed generics of the same generic type.

By default, the data contract name for a generic type is the name of the type, followed by the string "Of", followed by the data contract names of the generic parameters, followed by a hash computed using the data contract namespaces of the generic parameters. A hash is the result of a mathematical function that acts as a "fingerprint" that uniquely identifies a piece of data. When all of the generic parameters are primitive types, the hash is omitted.

For example, see the types in the following example.

[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 this example, the type Drawing<Square,RegularRedBrush> has the data contract name "DrawingOfSquareRedBrush5HWGAU6h", where "5HWGAU6h" is a hash of the "urn:shapes" and "urn:default" namespaces. The type Drawing<Square,SpecialRedBrush> has the data contract name "DrawingOfSquareRedBrushjpB5LgQ_S", where "jpB5LgQ_S" is a hash of the "urn:shapes" and the "urn:special" namespaces. Note that if the hash is not used, the two names are identical, and thus a name collision occurs.

Customizing data contract names for generic types

Sometimes, the data contract names generated for generic types, as described previously, are unacceptable. For example, you may know in advance that you will not run into name collisions and may want to remove the hash. In this case, you can use the DataContractAttribute.Name property to specify a different way to generate names. You can use numbers in curly braces inside of the Name property to refer to data contract names of the generic parameters. (0 refers to the first parameter, 1 refers to the second, and so on.) You can use a number (#) sign inside curly braces to refer to the hash. You can use each of these references multiple times or not at all.

For example, the preceding generic Drawing type could have been declared as shown in the following example.

[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 this case, the type Drawing<Square,RegularRedBrush> has the data contract name "Drawing_using_RedBrush_brush_and_Square_shape". Note that because there is a "{#}" in the Name property, the hash is not a part of the name, and thus the type is susceptible to naming collisions; for example, the type Drawing<Square,SpecialRedBrush> would have exactly the same data contract name.

See also