A data contract describes how CLR types map to XSD schema definitions.
Data contracts are the preferred way to enable serialization of complex types included in operation signatures as parameters or return values.
You create a data contract by applying the DataContractAttribute to a type.
To include members in serialization,you decorate them with the DataMemberAttribute;
this is an opt-in process that has nothing to do with visibility of members (public,protected,private).
By default,serialization is handled by the DataContractSerializer,a new serializer for WCF that succeeds the XmlSerializer used for earlier technologies such as ASMX.
In this section,you will become acquainted with the key features of data contracts and common serialization practices, including the following:
• How to apply data contract attributes to exercise control over type serialization
• Version tolerance and data contract versioning techniques
• Implementing IExtensibleDataObject to support version tolerance
• How to work with polymorphic types in the service contract
• How enumerations, arrays, and collections are serialized
First you’ll complete a lab that illustrates many of these scenarios,and then I’ll explain the related attributes and features in greater detail.
Lab: Working with Data Contracts
For this lab you will modify a preexisting type,turning it into a data contract so that it can be included in the service contract.
Using the DataContractAttribute and the DataMemberAttribute,you will control type serialization through the DataContractSerializer.
You’ll also test data contract version tolerance and implement the IExtensibleData interface in support of versioning.
Creating a data contract
In this part of the lab,you’ll turn a complex type into a data contract so that it can be included in a service contract,
and then take a look at the XSD schema produced for the type in the WSDL document.
1. Open the startup solution for this lab: <YourLearningWCFPath>\Labs\Chapter2\DataContracts\DataContracts.sln.
This solution includes the following projects:
ContentTypes
A class library that contains a LinkItem type used by the service.
LinkItem is a custom type that holds a title,description,URL and other details that can be associated with events,articles,photos,files,and so forth.
In this example, LinkItem is used to hold information about a gig (or event) for a band.
GigManager
A class library containing the service contract and service type.
The service contract exposes operations to save a LinkItem,and retrieve the saved LinkItem.
This example uses session to save the item.
See Chapter 5 for more on sessions.
Host
A console application for hosting the service.
GigEntry
A Windows client application that presents an interface for users to create and save a gig entry and retrieve the saved entry.
2. Try to run the solution at first.
From Visual Studio,press F5 to run the Host and the GigEntry client application.
An InvalidDataContractException will be thrown when the ServiceHost attempts to initialize. //这个地方是瞎扯,默认不会抛出异常的 ,虽然我用的是.net 3.0,也不会抛出异常
The error message indicates that the type ContentTypes.LinkItem cannot be serialized.
3. Review the service contract for the solution.
Go to the GigManager project and open GigManagerService.cs.
The service contract is shown in Example 2-13.
The ContentTypes.LinkItem type is included in both operation signatures.
Example 2-13. IGigManagerService service contract
[ServiceContract(Name = "GigManagerServiceContract", Namespace = "http://www.thatindigogirl.com/samples/2006/06", SessionMode = SessionMode.Required)]
public interface IGigManagerService
{
[OperationContract]
void SaveGig(LinkItem item); [OperationContract]
LinkItem GetGig();
}
4. You are going to modify the LinkItem type to make it a valid data contract that can be included in the service contract.
Go to the ContentTypes project and add a reference to the System.Runtime.Serialization assembly. //需要添加新的引用System.Runtime.Serialization
Next,open LinkItem.cs and apply the DataContractAttribute to the class definition,
and apply the DataMemberAttribute to each private field so that they are included in the serialized type definition.
Add a using statement for System.Runtime.Serialization as well.
The resulting type should appear as shown in Example 2-14.
给类添加DataContract 给是有字段添加DataMember
[DataContract]
public class LinkItem
{
[DataMember]
private long id;
public long ID
{
get { return id; }
set { id = value; }
} [DataMember]
private string title;
public string Title
{
get { return title; }
set { title = value; }
} [DataMember]
private string description;
public string Description
{
get { return description; }
set { description = value; }
} [DataMember]
private DateTime dateStart;
public DateTime DateStart
{
get { return dateStart; }
set { dateStart = value; }
} [DataMember]
private DateTime dateEnd;
public DateTime DateEnd
{
get { return dateEnd; }
set { dateEnd = value; }
} [DataMember]
private string url;
public string Url
{
get { return url; }
set { url = value; }
}
}
5. Compile the solution and attempt to run the host once again.
This time you won’t see an exception because LinkItem is now a data contract.
6. View the service description in the browser;
you want to see the XSD schema representation of the LinkItem data contract.
Browse to the following address:http://localhost:8000 and click the ?wsdl link to navigate to the service description.
This will generate the service description so that you can browse to the following address: http://localhost:8000/?xsd=xsd2.
You should see a schema like the one shown in Example 2-15.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/ContentTypes" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/ContentTypes">
<xs:complexType name="LinkItem">
<xs:sequence>
<xs:element minOccurs="0" name="DateEnd" type="xs:dateTime"/>
<xs:element minOccurs="0" name="DateStart" type="xs:dateTime"/>
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="ID" type="xs:long"/>
<xs:element minOccurs="0" name="Title" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="Url" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="LinkItem" nillable="true" type="tns:LinkItem"/>
</xs:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/ContentTypes" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/ContentTypes">
<xs:complexType name="LinkItem">
<xs:sequence>
<xs:element minOccurs="" name="dateEnd" type="xs:dateTime"/>
<xs:element minOccurs="" name="dateStart" type="xs:dateTime"/>
<xs:element minOccurs="" name="description" nillable="true" type="xs:string"/>
<xs:element minOccurs="" name="id" type="xs:long"/>
<xs:element minOccurs="" name="title" nillable="true" type="xs:string"/>
<xs:element minOccurs="" name="url" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="LinkItem" nillable="true" type="tns:LinkItem"/>
</xs:schema>
Notice that the naming convention for each data member matches the field name in the type definition.
In addition,the order of each element in the schema sequence is alphabetical, //每一个元素是按照字母顺序排列的
as opposed to the order of appearance in the type definition.
Another thing to note is that the namespace for the type does not match the service contract target namespace;
instead,it uses the domain shemas.datacontract.org.
Note:
Other .NET serialization techniques are dependent on the reflection order of types.
This can introduce problems when developers inadvertently reorder the class definition,not realizing it can cause incompatibilities.
Customizing data contract serialization 自定义数据契约的序列化
Now the LinkItem type is a valid data contract but you may want to provide a namespace consistent with the namespace in your service contract,indicating that this type belongs to your application.
Furthermore,you may want to provide more formal names for each of the data members.
Another thing you may want to control is the order in which members appear in the schema—recall that the default behavior is to present them in alphabetical order.
In this section,you’ll customize the data contract to address these issues.
1. Modify the LinkItem type definition to provide a proper namespace,friendly names for each data member,and appropriate order for data members in the
schema.
Start by supplying a Namespace value for the DataContractAttribute.
Also provide values for the following DataMemberAttribute properties: Name,IsRequired,and Order.
Example 2-16 provides you with the values to use for each attribute.
Pay attention to the IsRequired property for each.
It will be significant later in the lab.
Example 2-16. Customizing serialization with DataContractAttribute and DataMemberAttribute
[DataContract(Namespace="http://schemas.thatindigogirl.com/samples/2006/06")]
public class LinkItem
{
[DataMember(Name = "Id", IsRequired = false, Order = 0)]
private long m_id;
[DataMember(Name = "Title", IsRequired = true, Order = 1)]
private string m_title;
[DataMember(Name = "Description", IsRequired = true, Order = 2)]
private string m_description;
[DataMember(Name = "DateStart", IsRequired = true, Order = 3)]
private DateTime m_dateStart;
[DataMember(Name = "DateEnd", IsRequired = false, Order = 4)]
private DateTime m_dateEnd;
[DataMember(Name = "Url", IsRequired = false, Order = 5)]
private string m_url;
// Properties
}
2. Compile the host and run it without debugging. Return to the browser and review the new LinkItem schema by browsing to http://localhost:8000/?xsd=xsd2(be sure to refresh).
The schema should now look like the one shown in Example 2-17.
这一块也是无力吐槽了,我编译之后,访问http://localhost:8000/?xsd=xsd2和http://localhost:8000/出现的是同一个界面。没有下面所显示的内容
应该访问这个地址http://localhost:8000/?xsd=xsd0
Example 2-17. Schema generated for the modified LinkItem data contract
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified"
targetNamespace="http://schemas.thatindigogirl.com/samples/2006/06"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://schemas.thatindigogirl.com/samples/2006/06">
<xs:complexType name="LinkItem">
<xs:sequence>
<xs:element minOccurs="0" name="Id" type="xs:long" />
<xs:element name="Title" nillable="true" type="xs:string" />
<xs:element name="Description" nillable="true" type="xs:string" />
<xs:element name="DateStart" type="xs:dateTime" />
<xs:element minOccurs="0" name="DateEnd" type="xs:dateTime" />
<xs:element minOccurs="0" name="Url" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="LinkItem" nillable="true" type="tns:LinkItem" />
</xs:schema>
Now the elements in the schema use the formal property name and are presented in the order specified by each DataMemberAttribute.
Required and optional members also have an affect on the minOccurs schema attribute;
required elements use the implicit value for minOccurs, which is 1.
Leave the host running as you move to the next step in the lab.
Consuming data contracts at the client
Now it’s time to add some code to the client application to save and retrieve gig information using the LinkItem type.
In this section of the lab,you’ll see how SvcUtil generates data contracts for complex types exposed at the service.
1. Start by generating a proxy for the client.
Go to the GigEntry project and add a service reference supplying the base address for the GigManagerService: http://localhost:8000.
Use the namespace localhost.
2. Open GigInfoForm.cs in the code window and add the following code beneath the GigInfoForm definition to construct the proxy:
public partial class GigInfoForm : Form
{
localhost.GigManagerServiceContractClient m_proxy = new
GigEntry.localhost.GigManagerServiceContractClient( );
// other code
}
Find the cmdSave_Click() event and add code to create a LinkItem instance that will hold gig information input by the user.
Example 2-18 shows the code to initialize the LinkItem.
You must also add the using statement for GigEntry.localhost.
Example 2-18. Code to save a LinkItem
using GigEntry.localhost;
private void cmdSave_Click(object sender, EventArgs e)
{
LinkItem item = new LinkItem( );
item.Id = int.Parse(this.txtId.Text);
item.Title = this.txtTitle.Text;
item.Description = this.txtDescription.Text;
item.DateStart= this.dtpStart.Value;
item.DateEnd= this.dtpEnd.Value;
item.Url= this.txtUrl.Text;
m_proxy.SaveGig(item);
}
3. Now add code to the cmdGet_Click( ) event handler to retrieve the saved LinkItem storing gig information.
This code is shown in Example 2-19.
Example 2-19. Code to retrieve a previously saved LinkItem
private void cmdGet_Click(object sender, EventArgs e)
{
LinkItem item = m_proxy.GetGig( );
if (item != null)
{
this.txtId.Text = item.Id.ToString( );
this.txtTitle.Text = item.Title;
this.txtDescription.Text = item.Description;
if (item.DateStart != DateTime.MinValue)
this.dtpStart.Value = item.DateStart;
if (item.DateEnd != DateTime.MinValue)
this.dtpEnd.Value = item.DateEnd;
this.txtUrl.Text = item.Url;
}
}
4. Now you are ready to test the solution.
Compile the solution and run both the Host and GigEntry client application.
The GigEntry client application is prepopulated with some default values in the user interface (see Figure 2-5).
Select Save to populate a LinkItem with gig information and pass it to the SaveGig( ) service operation.
Clear some text from the description and select Get to retrieve the LinkItem you previously saved.
Figure 2-5. GigEntry client user interface
At this point,you have turned the LinkItem complex type into a data contract,exposed this type as part of the service description,and generated a client proxy to consume operations that rely on the LinkItem type.
To developers,the client code works directly with the LinkItem.
In fact,the service model relies on a client-side version of the data contract to handle serialization.
If you open the proxy,you’ll see a copy of the LinkItem data contract.
I’ll discuss this further after you complete the lab.
Exploring version tolerance
In this section,of the lab you’ll play with some data contract versioning scenarios.
You’ll add and remove items from the contract,and you’ll see what the limitations are on adding new parameters.
1. To begin with,remove one of the data members from the LinkItem data contract.
Open LinkItem.cs and comment the DataMemberAttribute for m_url:
//[DataMember(Name = "Url", Order = 5, IsRequired = false)]
private string url;
Compile and run the solution again and test the impact of this change.
In the GigEntry interface select Save,then select Get.
The URL textbox will be cleared because the value was lost at the service.
2. Change the LinkItem type so that it preserves unknown data elements provided by the client.
Modify the LinkItem class definition to inherit IExtensibleDataObject.
Implement the interface by adding the new ExtensionData member and property accessor shown in Example 2-20.
[DataContract(Namespace = "http://www.thatindigogirl.com/samples/2006/06")]
public class LinkItem : IExtensibleDataObject
{
private ExtensionDataObject extensionData;
public ExtensionDataObject ExtensionData
{
get
{
return extensionData;
}
set
{
extensionData = value;
}
}
//Other Code
}
Test the result of this change by compiling and running the solution once again.
From the GigEntry interface select Save. Clear the URL textbox and select Get.
This time, the URL you originally saved is returned.
3. Now add a new enum field to the data contract.
Open LinkItem.cs and add the enumeration defined in Example 2-21 to the ContentTypes namespace.
Example 2-21. Definition for LinkItemCategories
[DataContract(Namespace="http://schemas.thatindigogirl.com/samples/2006/06")]
public enum LinkItemCategories
{
[EnumMember]
Gig,
[EnumMember]
MP3,
[EnumMember]
Photo
}
Add the following required data member named LinkItemCategories to the LinkItem definition:
[DataMember(Name = "Category", IsRequired = true, Order = 6)]
public LinkItemCategories m_category;
Compile and run the solution again.
From the GigEntry interface,select Save;
this time a FaultException is thrown indicating an error while deserializing the message.
The error indicates that a different element was expected,which essentially means an expected field is missing or out of order.
格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://www.thatindigogirl.com/samples/2006/06 进行反序列化时出错: item。
InnerException 消息是““EndElement”命名空间“http://www.thatindigogirl.com/samples/2006/06”中的“item”并非所需元素。
所需元素应为“Category”。”。有关详细信息,请参阅 InnerException。
4. Change the definition so that the LinkItemCategories data member is no longer required:
[DataMember(Name = "Category", IsRequired = false, Order = 6)]
public LinkItemCategories m_category;
Compile and run the solution,executing the same test.
This time there won’t be an exception because the new data member,unknown to the client proxy,is no longer required.
Let’s take a closer look at the attributes and features used in this lab.
Mapping Data Contracts to XSD Schema
Data contracts included in service contracts become part of the service description and thus the WSDL document.
For each data contract included a schema is generated,and this schema is referenced by the operation messages that rely on the type.
In an operation signature that has multiple parameters and a return value,each may be a distinct data contract represented as individual schema.
Example 2-22 illustrates a schema generated for the LinkItem type (repeated from the lab). This schema describes the following:
• The target namespace of the serialized type.
Messages that include a serialized LinkItem will use this namespace to disambiguate from other LinkItem types if they exist.
• The definition of the type.
In the case of the LinkItem,the outer element name is <LinkItem> and it contains a sequence of child elements.
• The expected name for each child element.
• The data type of each child element.
Examples of schema types used in this schema are string, long, and dateTime.
• If the element is required or not as indicated by the minOccurs attribute.
If minOccurs is omitted,the implied value is 1.
If minOccurs is 0,the element may be omitted and the serialized type will still be valid against the schema.
• If the element can be empty or not as indicated by the nillable attribute.
If nillable is set to false, the element cannot be passed without contents.
• The layout order of each child element.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.thatindigogirl.com/samples/2006/06" elementFormDefault="qualified" targetNamespace="http://www.thatindigogirl.com/samples/2006/06">
<xs:import schemaLocation="http://localhost:8000/?xsd=xsd2" namespace="http://schemas.thatindigogirl.com/samples/2006/06"/>
<xs:element name="SaveGig">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="item" nillable="true" type="tns:LinkItem"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="LinkItem">
<xs:sequence>
<xs:element minOccurs="0" name="ID" type="xs:long"/>
<xs:element name="Title" nillable="true" type="xs:string"/>
<xs:element name="Description" nillable="true" type="xs:string"/>
<xs:element name="DateStart" type="xs:dateTime"/>
<xs:element minOccurs="0" name="DateEnd" type="xs:dateTime"/>
<xs:element xmlns:q1="http://schemas.thatindigogirl.com/samples/2006/06" minOccurs="0" name="Category" type="q1:LinkItemCategories"/>
</xs:sequence>
</xs:complexType>
<xs:element name="LinkItem" nillable="true" type="tns:LinkItem"/>
<xs:element name="SaveGigResponse">
<xs:complexType>
<xs:sequence/>
</xs:complexType>
</xs:element>
<xs:element name="GetGig">
<xs:complexType>
<xs:sequence/>
</xs:complexType>
</xs:element>
<xs:element name="GetGigResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="GetGigResult" nillable="true" type="tns:LinkItem"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Schema can also represent hierarchical relationships in the event a data contract inherits other base data contracts.
Each data contract would still have its own schema,but the inheritance hierarchy is preserved. Collections,dictionaries,and arrays are all represented in schema as arrays.
The WSDL document thus carries not only all the information about endpoints,protocols,and operations,it also includes schema for each complex type used by each operation.
That’s how SvcUtil is able to reconstruct data contracts during proxy generation.
Although the resulting types may not look exactly like those at the service,the reverse-engineered types will successfully be serialized into a format that the service can deserialize to reconstruct appropriate CLR types.
In some cases,you may be presented with a preexisting schema that should be used in your service contracts.
You can use SvcUtil to generate data contracts for this schema in the same way you use SvcUtil to generate a proxy for the client.
Designing Data Contracts
As the lab illustrates,to create a data contract you apply DataContractAttribute to your custom types and apply the DataMemberAttribute to each field or property you want to include in serialization.
This opt-in approach forces developers to consider what information should be transferred between clients and services.
The service model uses the DataContractSerializer to convert between data contracts and schema.
Any data contracts included in service operations are included in the service description.
Thus, proxy generation can generate copies of those types for client use.
DataContractAttribute and DataMemberAttribute each have properties that help you control the schema generated for a complex type.
There are also other attributes that support enumerations and collections,specifically.
They are the EnumMemberAttribute and the CollectionDataContractAttribute,respectively.
In this section I’ll talk about each of these attributes and their relevance to serialization.
DataContractAttribute
The DataContractAttribute is part of the System.Runtime.Serialization namespace.
As discussed earlier,it is used to turn complex types into data contracts to support service model serialization.
This attribute has only two properties:
Name
Controls the complex type name generated for the schema. By default the CLR type name is used.
Namespace
Sets the target namespace for the schema.
This defaults to http://schemas.datacontract.org/2004/07/[CLR namespace].
The CLR namespace is the namespace in which the complex type is defined.
Setting each of these properties can be important since the desired schema conventions may not align with CLR naming conventions developers use.
At a minimum,you should provide a value for Namespace.
By default,the namespace used for data contracts uses the prefix http://schemas.datacontract.org/2004/07.
Like with the target namespace for the service,complex types described in schema should have a namespace that relates the type to your specific company or application.
This can also help to resolve ambiguities if other types are used with the same name.
A common convention in web service specifications is to take the target namespace for the service and replace “www” (for example) with “schemas.” The lab illustrates this pattern:
[DataContract(Namespace="http://schemas.thatindigogirl.com/samples/2006/06")]
DataMemberAttribute
The DataMemberAttribute is also part of the System.Runtime.Serialization namespace.
This attribute is used to opt-in the field or properties to be included in serialization.
This attribute provides several properties for controlling the resulting schema generated for a complex type:
Name
Controls the schema element name generated for the field or property.
The default behavior is to use the field or property name as defined in the CLR type.
IsRequired
Controls the minOccurs attribute for the schema element.
By default,all elements are optional (minOccurs=0).
Order
Controls the order of each element in the schema.
By default,nonordered data members appear alphabetically, followed by any ordered elements.
EmitDefaultValue
Controls if default values will be included in serialization.
By default,all data members are serialized.
If this property is set to false,any member that is set to the default value for its type (null reference types,for example) will not be serialized.
This can cause problems if IsRequired is set to true.
By default all data members are ordered alphabetically,they carry the name of the associated field or property,and they become nonrequired schema elements.
In this section, I’ll explain how to control these characteristics.
You can apply the DataMemberAttribute to a field or property definition regardless of visibility (public,protected,private).
Applying the DataMemberAttribute to properties enables you to serialize values that may not have field storage (they may be dynamically calculated at runtime).
In either case,this attribute explicitly includes the field or property in the data contract.
It can be confusing if you mix the application of this attribute among fields and properties,
so I recommend that you generate property accessors for all fields (public,protected,private)
so that you can apply the attribute to properties instead of fields.
If you name your properties in such a way that they also fit naming conventions for the schema,
you needn’t set the Name property of this attribute.
Note:
If you apply the DataMemberAttribute to both property and its associated field,
you’ll end up with duplicate members in the schema.
By default,data members are not required.
That means if the client fails to supply a value,the complex type will be initialized with defaults for those members.
If you require certain fields to operate,you should set the IsRequired property to true.
IsRequired affects the minOccurs attribute for the associated element in the schema.
If messages arrive with missing required elements the service model throws an exception,something this lab illustrates.
If you introduce new required fields to a complex type after version 1 of the contract has been published,existing clients will not be compatible.
To support backward compatibility,you should not make new data members required.
I’ll talk more about versioning practices shortly.
The nillable schema attribute cannot be controlled by a DataMemberAttribute property.
The default behavior is that reference types have nillable set to true,while value
types (structures) have nillable set to false.
This is illustrated in Example 2-17; string elements are nillable, dateTime elements are not.
You can modify this behavior by using the nullable type in .NET.
The following code shows you how to declare a nullable type using shorthand (“?” suffix) or the more formal notation with Nullable<T>:
[DataMember(Name = "DateEnd", IsRequired = false, Order = 4)]
private DateTime? m_dateEnd;
public Nullable<DateTime> DateEnd
{
get { return m_dateEnd; }
set { m_dateEnd = value; }
}
The resulting schema will now support empty values for the DateEnd element:
<xs:element minOccurs="0" name="DateEnd" nillable="true" type="xs:dateTime" />
Note:
A sample illustrating Nullable<T> can be found at <YourLearningWCFPath>\Samples\DataContracts\NullableTypes.
You can also control the order that elements appear in the schema.
By default,the DataContractSerializer generates a schema for each data contract with data member order based on the following rules:
• Starting from the topmost class in the hierarchy and working down through the inheritance tree.
• Within each individual data contract, data members are ordered alphabetically.
• Any data members with a specified order will be ordered alphabetically within the order grouping.
For example,ordered elements can be grouped within a type such that all members with Order=1 are alphabetical,followed all members with Order=2, and so on.
To simplify matters,developers should apply an explicit order to each data member,within a type.
After all,how does it look to business partners that consume your services if the Id field is in the middle of the elements in the schema instead of at the top?
What happens when there are 100 elements in a complex type and there is no sense to its organization?
Note:
If you need greater control over the resulting schema for a complex type or hierarchy of types,you should consider using the IXmlSerializable approach.
I’ll discuss this later in this chapter.
The important thing to consider is that naming conventions and element order for data contracts should be consistent and professional.
Note:
Here are several samples related to DataContractAttribute and DataMemberAttribute:
• <YourLearningWCFPath>\Samples\DataContracts\DataContracts_FieldMembers
• <YourLearningWCFPath>\Samples\DataContracts\DataContracts_PropertyMembers
EnumMemberAttribute
Enumerations are implicitly data contracts,which means you don’t have to decorate them with the DataContractAttribute in order to expose them in a service contract.
By default,all members are included in the schema for the enumeration,and the default namespace will use the prefix http://schemas.datacontract.org/2004/07.
To be consistent with your other data contracts,you should probably provide a namespace for your enumerations,as shown in Example 2-21 from this lab.
But,once you decorate enumerations with DataContractAttribute you are obligated to opt-in each member you want to include in the enumeration.
There is a catch to this: you must use the EnumMemberAttribute instead of the DataMemberAttribute.
Note:
Using the DataMemberAttribute will result in an empty schema definition for the enumeration.
The resulting schema definition for the LinkItemCategories enumeration in this lab is shown in Example 2-23.
Example 2-23. Schema generated for LinkItemCategories
<xs:simpleType name="LinkItemCategories">
<xs:restriction base="xs:string">
<xs:enumeration value="Gig" />
<xs:enumeration value="MP3" />
<xs:enumeration value="Photo" />
</xs:restriction>
</xs:simpleType>
The EnumMemberAttribute has a single property, Value.
You can use this property to control how enum members are named in the schema:
[EnumMember(Value="Event"]
Gig,
[EnumMember(Value="Music"]
MP3,
[EnumMember(Value="Pics"]
Photo
CollectionDataContractAttribute
You may need to create a custom collection at some point,and expose it as part of a service contract.
The CollectionDataContractAttribute is a special attribute specifically for this purpose.
This attribute has the following members:
Name
Controls the collection type name generated for the schema.
By default,the CLR type name is used.
Namespace
Sets the target namespace for the schema with default behavior like the DataContractAttribute.
ItemName
Controls the name for each element in the collection.
KeyName
Controls the key name for dictionary collections only. This is invalid if the collection type is not a dictionary.
ValueName
Controls the value name for dictionary collections only. This is invalid if the collection type is not a dictionary.
You apply the CollectionDataContractAttribute to the custom collection like this:
[CollectionDataContract(Namespace=
"http://schemas.thatindigogirl.com/samples/2006/06",ItemName="Item")]
public class LinkItemCollection: List<LinkItem>
{ }
A sample illustrating CollectionDataContractAttribute can be found at
<YourLearningWCFPath>\Samples\DataContracts\CollectionDataContract.