Introduction

Contract = Agreement,

Data Contract = Data Agreement,

Data Agreement between whom? The agreement between the client and the server.

What exactly does the agreement contain? The structured data to be exchanged between the client and the server.

I hope you guys understand the preceding lines, yes a Data Contract is an agreement between the client and server about the structure of data being exchanged. A Data Contract describes the external format, structure and type of data being exchanged. It also defines how the data types are serialized and deserialized. The serialization happens on the client side to convert the objects into the messages that can be streamed over the network. On the other hand the dispatcher in the server side performs deserialization to convert the objects into data types and pass it to the service methods for execution. To understand the various stages of data transfer from a client to a server and how the parameters are converted into objects and the objects converted into messages, kindly refer to my previous article "WCF Run Time Architecture".

DataContractSerializer

WCF uses the DataContractSerializer class from the namespace System.RunTime.Serialization to serialize and deserialize the objects. This serializer is specially developed for WCF to perform quickly, effectively and powerfully.

DataContractSerializer supports the following data types:

  • Primitive data types
  • Data types with the [DataContract] attribute
  • Class marked as Serializable
  • Class that implements the IXmlSerializable
  • Enumerations, collections and generic collections

Primitive data types are already serializable, so no serialization measures are required for the primitive data types. Apart from the primitive types, whatever the complex types are used as parameters, return values in the service, we need to treat the class with the [DataContract] Attribute and the properties and member variables with the [DataMember] attribute. These attributes are actually used by the DataContractSerializer class to control the serialization/deserialization. In other words, these two attributes tell the Datacontractserializer how to serialize the complex types. [DataContract] is an opt-in model which means that only the member variables or properties that are marked with [DataMember] will be taken for the Serialization/Deserialization. The definition of the data is incorporated into the WSDL document in an XSD format.

Source Code Explanation

  1. Interface in Service   

  2. [ServiceContract(Namespace = "http://Rameshkartik/WCFSamples/OnlineShoppingService",  
  3.      Name = "OnlineShoppingService")]  
  4.     public interface IOnlineShoppingService  
  5.     {  
  6.         [OperationContract(Name = "StockAvailability")]  
  7.         bool IsStockAvailable(string sModelNumber);  
  8.   
  9.         [OperationContract(Name = "CalculatePrice",   
  10.          ProtectionLevel = System.Net.Security.ProtectionLevel.None)]  
  11.          double CalculatePrice(string sModelNumber, int iQuantity, string sDeliveryLocation);  
  12.   
  13.         [OperationContract(Name = "GetWholeSaleDealerInfo")]  
  14.         WholeSaleDealersInfo GetwholeSaleDealerInfo(string sFilterByCity);  
  15.   
  16.     }  

Look at the code snippet above, in the service interface we have exposed three methods called IsStockAvailable, CalculatePrice and GetWholeDealerInfo. Notice that the return type of the GetWholeSaleDealerInfo method is WholeSaleDealersInfo type, which is a complex type. We need to tell the DataContractSerializer about the complex type WholeSaleDealersInfo to serialize/deserialize.

  1. DataContract WholeSaleDealersInfo  
  2.   
  3.    
  4. [DataContract]  
  5.     public class WholeSaleDealersInfo  
  6.     {  
  7.         private string sDealerName;  
  8.         private string sDealerLocation;  
  9.         private DateTime sDealerSince;  
  10.         private int iDealerAge;  
  11.   
  12.         [DataMember]  
  13.         public string DealerName  
  14.         {  
  15.             get { return sDealerName; }  
  16.             set { sDealerName = value; }  
  17.         }  
  18.   
  19.         [DataMember(Name="LocationofDealer",Order=3,IsRequired = true,   EmitDefaultValue=true)]  
  20.         public string DealerLocation  
  21.         {  
  22.             get { return sDealerLocation; }  
  23.             set { sDealerLocation = value; }  
  24.         }  
  25.            }  
Look at the code snippet above, the class has been decorated with the attribute [DataContract] and the properties as [DataMember]. This decoration is to tell the DataContractSerializer how and in which form its objects are to be converted.

Parameter Order

There is an attribute called Order in the Datamember where you can define the order of serialization and deserialization. Sometimes a datacontract should be serialized and deserialized in a specific order of data members.

By default the data members are serialized and deserialized in the following order:

  1. If the DataContract has been derived from the base DataContract then the data members of the base class will be processed first in alphabetical order
  2. DataMembers with no order property set will be processed in alphabetical order
  3. The remaining DataMembers will be processed in ascending order of the Order property value

Parameter Name

Using the DataMember Attribute, we can define the name of a DataMember on each property. It will be helpful to solve the DataContract versioning issues. The following source code will provide you a better understanding of this attribute.

  1. // Version 1 of DataContract Order  
  2.     [DataContract]  
  3.     public class Order  
  4.     {  
  5.         [DataMember]  
  6.         private string OrderID;  
  7.   
  8.         [DataMember]  
  9.         private string Name;  
  10.     }  
  11.   
  12.     // Version 2 of DataContract Order  
  13.     [DataContract]  
  14.     public class Order  
  15.     {  
  16.         [DataMember]  
  17.         private string OrderID;  
  18.   
  19.         [DataMember(Name = "Name")]  
  20.         private string EmployeeName;  
  21.     }  
Parameter IsRequired, EmitDefaultValue

By Default the IsRequired field will be false, if it is true then that specific property must be available during the serialization or deserialization process. If the IsRequired field is true and the EmitDefaultValue is true and if the value doesn't provide the default value then it will be taken during the serialization. If the IsRequired field is true and the EmitDefaultValue is false and if the value doesn't provide the default value then it will not be taken during the serialization and the serialization exception will be thrown.

Next Recommended Readings