Two data contracts are considered equivalent if they have the same wire representation—that is, if they have the same infoset schema. This can be the case if they define the same type (but not necessarily the same version of the type), or if the two data contracts refer to two different types with the same data contract and data member names. Equivalent data contracts are interchangeable: WCF will let any service that was defined with one data contract operate with an equivalent data contract.
The most common way of defining an equivalent data contract is to use the DataContract
and DataMember
attributes' Name
properties to map one data contract to
another. In the case of the DataContract
attribute, the
Name
property defaults to the type's name, so these two
definitions are identical:
[DataContract] struct Contact {...} [DataContract(Name = "Contact")] struct Contact {...}
In fact, the full name of the data contract always includes its namespace as well, but as you have seen, you can assign a different namespace.
In the case of the DataMember
attribute, the Name
property defaults to the member name, so these two
definitions are identical:
[DataMember] string FirstName; [DataMember(Name = "FirstName")] string FirstName;
By assigning different names to the data contract and data members, you can generate an equivalent data contract from a different type. For example, these two data contracts are equivalent:
[DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } [DataContract(Name = "Contact")] struct Person { [DataMember(Name = "FirstName")] public string Name; [DataMember(Name = "LastName")] public string Surname; }
In addition to having identical names, the types of the data members have to match.
A class and a structure that support the same data contract are interchangeable.
In classic .NET, a subclass can define a member of the same name and type as a private member of its base class, and in turn, its own subclass can do the same:
class A { string Name; } class B : A { string Name; } class C : B { string Name; }
If the class hierarchy is also a data contract, this presents a problem when serializing into a message an instance of the subclass, since the message will contain multiple copies of a data member with the same name and type. To distinguish between them, WCF places the data members in the message in a particular order.
The default serialization order inside a type is simply alphabetical, and across a
class hierarchy the order is top-down. In case of a mismatch in the serialization order,
the members will be initialized to their default values. For example, when serializing a
Customer
instance, defined as:
[DataContract] class Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } [DataContract] class Customer : Contact { [DataMember] public int CustomerNumber; }
the members will be serialized in the following order: FirstName
, LastName
, CustomerNumber
.
Of course, equivalent data contracts must serialize and deserialize their members in
the same order. The problem now is that combining a data contract hierarchy with aliasing
contracts and members might break the serialization order. For example, the following data
contract is not equivalent to the Customer
data
contract:
[DataContract(Name = "Customer")] public class Person { [DataMember(Name = "FirstName")] public string Name; [DataMember(Name = "LastName")] public string Surname; [DataMember] public int CustomerNumber; }
because the serialization order is CustomerNumber
,
FirstName
, LastName
. To resolve this conflict, you need to provide WCF with the order of
serialization by setting the Order
property of the
DataMember
attribute. The value of the Order
property defaults to −1
, meaning the default WCF ordering, but you can assign to it values
indicating the required order:
[DataContract(Name = "Customer")] public class Person { [DataMember(Name = "FirstName",Order = 1
)] public string Name; [DataMember(Name = "LastName",Order = 2
)] public string Surname; [DataMember(Order = 3
)] public int CustomerNumber; }
When renaming data members, you must take care to manually change their order. Even
without renaming, with a large number of data members, the sorting can quickly get out of
hand. Fortunately, if another member has the same value for its Order
property, WCF will order them alphabetically. You can take advantage of
this behavior by assigning the same number to all members coming from the same level in
the original class hierarchy, or, better yet, simply assign them their levels in that
hierarchy:
[DataContract(Name = "Customer")] public class Person { [DataMember(Name = "FirstName",Order =1
)] public string Name; [DataMember(Name = "LastName",Order =1
)] public string Surname; [DataMember(Order =2
)] public int CustomerNumber; }
3.145.174.253