I have recently been doing a lot of work with the DataContractJsonSerializer and ended up writing some code that others may find useful. I had a base class which had some behaviors.  Anyone deriving from my base class needed to set some properties.  At first I did this in the constructor of the base class, like this:

public class DerivedObject : AbstractObject
{
    public DerivedObject()
        : base("derived object name!", "1001")
    {
    }

}

This pattern ensured that anyone deriving from my Abstract class would be forced to set these properties

However, I learned that, during deserialization, the constructor never got called. This killed my design. But, I learned about an attribute called OnDeserializing which I could decorate a method with.  Basically, this attribute forces a method to get called upon deserialization. So, I changed my design to use a custom attribute, which had the same effect as the constructor.  The signature for my derived object was changed to this:

 

[DataContract]
[Init("derived object name!", "1001")]
public class DerivedObject : AbstractObject
{

}

Then, I created a method in my abstract class which is decorated with the OnDeserializing attribute, which will then gets called. Note that you have to create your method signature with a parameter of type StreamingContext. I also call the Init() in the ctor of the abstract class, for the case when the object is newed up through normal instantiation:

[DataContract]
[KnownType (typeof(DerivedObject))]
public abstract class AbstractObject
{
    public AbstractObject()
    {
        Init();
    }

    [OnDeserializing]
    private void Init(StreamingContext c)
    {
        Init();

    }

    private void Init()
    {
        Type t = this.GetType();
        object[] customAttributes = t.GetCustomAttributes(false);
        InitAttribute initAttribute = null;
        foreach (object o in customAttributes)
        {
            if (o.GetType() typeof(InitAttribute))
                initAttribute = (InitAttribute)o;

        }
        if (initAttribute null)
            throw new Exception("Derived class must use InitAttritbute");
        this.name = initAttribute.Name;
        this.id = initAttribute.Id;

    }

}

Note the KnownType attribute, which is essential when creating derived classes from a base class that support serialization. In the Init() method, I rip out the values from the attribute, setting them on the object. With the above code, I can be sure that the object gets initialized correctly upon deserialization, as such:

static void ReadObject()
{
    string json = string.Empty;
    using (FileStream fs = new FileStream("json.txt", FileMode.Open))
    {
        using (StreamReader sr = new StreamReader(fs))
        {
            json = sr.ReadToEnd();
        }
    }

    Stream s = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json));
    derivedObject = abstractObjectSerializer.ReadObject(s) as DerivedObject;
    Console.WriteLine(derivedObject.Name);
    Console.WriteLine(derivedObject.Id);
    Console.WriteLine(derivedObject.Body);

    Console.ReadLine();

}

Here’s the whole sample if you are interested.