datacontract serialization and assertions

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!



0 comments: