Billy McCafferty wrote a recent post on WCF and the problem with hidden serialization exceptions. This struck a cord with me as I realised that one thing that I always tend to leave out in my WCF scenarios is asserting that the type continues to remain serializable throughout iterative development.
I decided to take a look at how I might include this in my normal test first process and here's what I came up with:
[Observations] public class when_serializing_my_object : observations_for_a_sut_without_a_contract<MyObject> { private static string propertyValue; private static MyObject returnedInstance; private context c = () => propertyValue = "aValue"; public override MyObject create_sut() { return new MyObject() { MyProperty = propertyValue }; } private because b = () => returnedInstance = sut.DataContractSerializeAndDeserialize(); [Observation] public void should_serialize_through_wcf() { returnedInstance.should_not_be_null(); } [Observation] public void should_have_correct_property_value() { returnedInstance.MyProperty.should_not_be_null(); returnedInstance.MyProperty.should_be_equal_to(propertyValue); } } [DataContract] public class MyObject { public string MyProperty { get; set; } }
I have a dummy class set up with one property and I am asserting that an instance is returned and that the correct property value is returned also.
The method I am using is a new extension method I created for this purpose:
public static class SerializeExtensions { public static T DataContractSerializeAndDeserialize<T>(this T instance) { var stream = new MemoryStream(); var dataContractSerializer = new DataContractSerializer(typeof(T)); dataContractSerializer.WriteObject(stream, instance); stream.Position = 0; var newInstance = (T)dataContractSerializer.ReadObject(stream); stream.Dispose(); return newInstance; } }
This uses the default WCF serialization class DataContractSerializer to serialize and then deserialize the instance of type T and is fairly straightforward.
When I run the tests I get a failure - this is correct because the MyObject class is decorated with the [DataContract] attribute but the MyProperty property is not decorated with [DataMember] at this time and including that attribute makes the test pass as I would expect.
What is unexpected is that taking the attributes off the class and property also causes the tests to pass... isn't DataContractSerialization supposed to be an opt-in only?.
Took me a while to find it, but it appears that in 3.5 SP1 there was a change so that by default any class without decorating attributes will be serialized by the DataContractSerializer So much for the opt-in part.
I'll be looking to include this in my next set of WCF classes and hoping it provides some pre-emptive support for hidden serialization issues - and thanks Billy!