DataContractSerializer (DCS) is the class that is used by WCF to serialize and deserialize messages when you make service calls. It is also sometimes used on its own to read and write objects to a stream, such as inside the WinRT SuspensionManager class. It works great and is very powerful, even being able to handle circular references inside the object graph that you are serializing (such as a parent object having a collection of child objects inside a collection property, and each of the child objects having a parent object reference through a navigation property). The DCS supports several kinds of serialization: based on Serializable/ISerializable, explicit data contract (using [DataContract] and [DataMember] attributes), and implicit data contracts (public type with public properties).
Depending on your point of view and usage, sometimes it is better to use explicit data contracts and sometimes it is better/easier to use implicit data contracts. However, there is a subtle gotcha that you should be aware of in terms of the construction process of the objects when deserializing an implicit vs an explicit data contract.
When an object with implicit data contract on it (public type and public properties involved in the serialization/deserialization) is deserialized, everything happens as you would expect – a new object instance is created, the constructor is called, and it can do any initialization of members that it wants to.
When an object with explicit data contracts on it ([DataContract] on the type, [DataMember] on the properties involved in serialization/deserialization) is deserialized, the constructor does not get called. As a result, any initialization that the constructor normally does (such as initializing private member variables that do not participate in the deserialization) will not be done on deserialization. If you need to do some initialization on deserialization, you can use OnDeserializing/OnDeserialized hooks. That means if you have some common initialization that you want called both when explicitly constructed (new’ed up) and when deserialized, you need to factor that initialization into a helper method and call that from both places to avoid duplication of code.
To see this in action, consider the following two entity types:
– Inline initialization of one private member variable
– Constructor initialization of another private member variable
– Console output when constructor is called
– Accessor functions for the private member variables
Now lets look at some code that serializes and deserializes these types with DCS:
The console output proves the difference in lifetime:
Notice that the constructor of the ExplicitContractEntity does not get called during the deserialization, but the ImplicitContractEntity constructor does, and as a result both the inline initialized variable and the one initialized in the constructor are null in the ExplicitContractEntity after deserialization whereas the ImplicitContractEntity ones are intact.
So the bottom line?
Be aware of the differences in construction / initialization between the two kinds of data contract
Be very careful about going and changing code that was using implicit data contracts to start using explicit data contracts. It is too easy to forget or to miss that things that were happening in the constructor during deserialization before are going to stop being called as soon as you switch to explicit data contracts.
If you want to learn more about the fundamentals of WCF, please check out my WCF Jumpstart course on Pluralsight.
You can download the full source code for this article here.