Be-Aware of differences in explicit and implicit deserialization with DCS

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:

1:publicclass ImplicitContractEntity

2: {

3:privatestring _someRefMember;

4:privatestring _someOtherRefMember = "Initialized";

5:public ImplicitContractEntity()

6: {

7: Console.WriteLine("Constructor of ImplicitContractEntity called");

8: _someRefMember = "InitializedName";

9: }

10:

11:publicint Id { get; set; }

12:publicstring Name { get; set; }

13:

14:publicstring GetPrivateRefMember()

15: {

16:return _someRefMember;

17: }

18:

19:publicstring GetPrivateOtherRefMember()

20: {

21:return _someOtherRefMember;

22: }

23:

24: }

25:

26: [DataContract]

27:publicclass ExplicitContractEntity

28: {

29:privatestring _someRefMember;

30:privatestring _someOtherRefMember = "Initialized";

31:public ExplicitContractEntity()

32: {

33: Console.WriteLine("Constructor of ExplicitContractEntity called");

34: _someRefMember = "InitializedName";

35: }

36: [DataMember]

37:publicint Id { get; set; }

38: [DataMember]

39:publicstring Name { get; set; }

40:

41:publicstring GetPrivateRefMember()

42: {

43:return _someRefMember;

44: }

45:

46:publicstring GetPrivateOtherRefMember()

47: {

48:return _someOtherRefMember;

49: }

50: }

You can see that the first is an implicit data contract (no DataContract or DataMember, all public properties will be serialized) and the second has explicit data contracts. You can also see that they have exactly the same structure including:

– 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:

1:staticvoid Main(string[] args)

2: {

3: Console.WriteLine("Constructing initial entities");

4: ExplicitContractEntity expEntity = new ExplicitContractEntity { Id = 42, Name = "Fred" };

5: ImplicitContractEntity impEntity = new ImplicitContractEntity { Id = 43, Name = "Wilma" };

6: DataContractSerializer expSerializer = new DataContractSerializer(expEntity.GetType());

7: DataContractSerializer impSerializer = new DataContractSerializer(impEntity.GetType());

8: Console.WriteLine();

9:using (MemoryStream expStream = new MemoryStream())

10: {

11: expSerializer.WriteObject(expStream, expEntity);

12: expStream.Position = 0;

13: Console.WriteLine("Deserializing explicit contract entity.");

14: ExplicitContractEntity deserializedExpEntity =

15: expSerializer.ReadObject(expStream) as ExplicitContractEntity;

16:

17:if (deserializedExpEntity.GetPrivateRefMember() null)

18: Console.WriteLine("Explicit contract private member null");

19:if (deserializedExpEntity.GetPrivateOtherRefMember() null)

20: Console.WriteLine("Explicit contract other private member null");

21: }

22: Console.WriteLine();

23:using (MemoryStream impStream = new MemoryStream())

24: {

25: impSerializer.WriteObject(impStream, impEntity);

26: impStream.Position = 0;

27:

28: Console.WriteLine("Deserializing implicit contract entity.");

29:

30: ImplicitContractEntity deserializedImpEntity =

31: impSerializer.ReadObject(impStream) as ImplicitContractEntity;

32:

33:if (deserializedImpEntity.GetPrivateRefMember() null)

34: Console.WriteLine("Implicit contract private member null");

35:if (deserializedImpEntity.GetPrivateOtherRefMember() null)

36: Console.WriteLine("Implicit contract other private member null");

37: }

38: Console.WriteLine("Hit any key to exit");

39: Console.ReadKey();

40: }

As you can see it first constructs an instance of each entity type, then it serializes and deserializes each, with some console output along the way to indicate the stages and to check whether the deserialized version of the objects has null values in its private member variables (through the accessor functions).

The console output proves the difference in lifetime:

2014-09-29_10-06-02

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?

  1. Be aware of the differences in construction / initialization between the two kinds of data contract

  2. 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.