Joe White’s Blog

Life, .NET, and Cats


Making DataContractSerializer play nice with UpdateControls

I’m really psyched about UpdateControls. I haven’t used it in too many projects yet, but it’s already changing the way I think about INotifyPropertyChanged, and opening new horizons yet unexplored.

(If you’re not familiar with UpdateControls, here’s my intro. tl;dr: If you do MVVM, you want to learn about UpdateControls. And it’s free.)

But UpdateControls just takes care of what happens between your model and your viewmodel and your view. There are other concerns your app has to figure out too, like moving data between your model and some kind of persistent storage. I’m writing a game, so I don’t have a database back-end or a service tier; I just want to save state to a local file. Sounds like a job for DataContractSerializer.

Simple enough, right? I just slap a [DataContract] attribute on my model, [DataMember] on all the public properties, and write it out, no problem. Then I try to load it back in, and… my app promptly crashes with a NullReferenceException. What went wrong?

War of the Constructors

The crux of the problem is that an UpdateControls-based model has to do some initialization in its constructor before you can start using its properties, whereas DataContractSerializer doesn’t acknowledge that the constructor even exists.

Recall that, when you define a model object using UpdateControls, you wrap each of your data fields in an Independent<T> that handles the bottom half of the notification magic. Our model object looks something like this:

[DataContract]
public class FooModel {
    private readonly Independent<bool> _active = new Independent<bool>();
    [DataMember]
    public bool Active {
        get { return _active; }
        set { _active.Value = value; }
    }

Notice that the _active field is initialized to a new instance of Independent<bool>. When this code is compiled, that assignment actually gets inserted at the beginning of the IL for FooModel’s constructor(s).

DataContractSerializer, when it deserializes a stream back into an object, doesn’t call any constructors; it just grabs an empty hunk of memory and calls it an object. I don’t know why it skips the constructors; it makes things awfully weird — as well as making it hard to delegate the property’s storage to another object, like you do with UpdateControls. Since FooModel’s constructor never ran, _active is null; so when the deserializer tries to set the Active property, the _active.Value assignment causes a NullReferenceException.

You can get different behavior by removing the [DataContract] attribute and serializing the object as a Plain Old CLR Object (POCO). If you’re deserializing a POCO, DataContractSerializer actually will call the constructor. But, it won’t serialize sub-objects — for POCOs, it looks like it only operates on properties with primitive types. No good for me — I don’t want to cram my entire application’s state into a single object.

Classic solution: Persistence objects

If I was using Entity Framework, I wouldn’t even be thinking about saving my model objects directly; I’d already have a separate set of entity classes that represent tables in the database. These classes wouldn’t depend on UpdateControls, and I’d have to manually copy the data between my model and my entity objects. Similarly, if I was saving to a service tier in a multi-tier application, I’d have the same situation with data transfer objects: I’d have to copy my model object’s contents to a DTO and back.

I could do the same thing with DataContractSerializer. I could define some persistence classes — dumb data contracts that are only used to save and load — and then copy data between those and my models.

The thing is, that “copy data back and forth” step is (a) hard, (b) boring, and (c) easy to screw up. I strive to be constructively lazy, and hard/boring/easy-to-screw-up is high on my list of things to avoid.

At work, we automate the hard/boring parts (and unit-test the easy-to-screw-up parts) with AutoMapper, which works really well. I think it would play pretty nicely with UpdateControls. But there isn’t (yet?) a WinRT version of AutoMapper, so that won’t help me with my WinRT app.

And even if I could use AutoMapper, it feels redundant to make a whole separate set of classes, with all the same properties as my model objects, unless it’s absolutely required by some persistence framework. Even if AutoMapper was there to remove the grunt work (and warn me when I forget to add a property to my persistence object), creating all those extra classes still feels unnecessary. DataContractSerializer should be able to serialize objects; that’s its job. The only problem is that it doesn’t run any of our initialization code. If that was solvable, we’d be golden.

OnDeserializing

If you poke around the System.Runtime.Serialization namespace, you’ll find the OnDeserializingAttribute.

The documentation for this attribute is pretty vague: it just says that it lets you designate a method to be “called during deserialization of an object”. When during deserialization? Before any fields are deserialized? After all the fields?

But since there’s also an OnDeserializedAttribute, I think I’m fairly safe in guessing that these follow the usual pattern: first the -ing method is called, then some other work (deserializing the object’s properties) is done, then finally the -ed method is called. Assuming that’s true (and I think it is, since my tests are passing), then you can use it to make a constructor stand-in for deserialization.

So you can make these changes:

  1. Add a new method called InitFields.
  2. Remove all the initialization expressions from the field declarations, and move those assignments into InitFields.
  3. Remove the readonly from the fields, since they’re now being assigned in a method, not in the constructor.
  4. Add an OnDeserializing method and tag it with [OnDeserializing], and give it a parameter of type StreamingContext. (I don’t know what the parameter is for, but you get a runtime error if it’s not there.)
  5. Call InitFields from both your constructor and your OnDeserializing method.

If you’re using ReSharper, then you’ll also want to add the JetBrains.Annotations NuGet package, and mark the OnDeserializing method as [UsedImplicitly] so ReSharper doesn’t warn you about the unused parameter.

Et voilà — you now have an UpdateControls-based model that you can serialize and deserialize successfully with DataContractSerializer! Here’s what it looks like:

[DataContract]
public class FooModel {
    private Independent<bool> _active;
    private void InitFields() {
        _active = new Independent<bool>();
    }
    public FooModel() {
        InitFields();
    }
    [OnDeserializing, UsedImplicitly]
    private void OnDeserializing(StreamingContext context) {
        InitFields();
    }
    [DataMember]
    public bool Active { ... }

This works, but it feels a bit clumsy, what with the extra two methods, and the assignments being separated from the field declarations. Just for fun, I decided to see if I could go one better.

Automating the process

Why not make a base class that uses Reflection to find all of our Independent<T> fields, and instantiate them automatically as needed?

My first thought was to plug this logic into both the constructor and OnDeserializing. Here’s what a model would look like in that case:

// Note: this example isn't compatible with the final version of SerializableModel
[DataContract]
public class FooModel : SerializableModel {
    [UsedImplicitly] private readonly Independent<bool> _active;
    [DataMember]
    public bool Active { ... }

If the base constructor instantiates the Independent<T>s for us, then _active doesn’t need an initializer anymore. But then ReSharper’s static analysis warns us that the field is never assigned, and we need to suppress the warning by adding an attribute to tell it that the field is used implicitly (i.e., via Reflection).

I thought I was being clever by removing all the “duplicate code” of Independent<T> instantiation, but ReSharper’s warning was my first hint that no, this really wasn’t technical elegance — it was a code smell. And after playing around with it for a couple of days, I had to agree.

It comes down to cognitive load. Our brains are only so big. When the code does what it says, you don’t have to waste as much of your brain capacity on technical minutiae; you have more brainpower available to actually solve the problems at hand. It’s not worth “removing duplication” if it means the code no longer does what it says. Any time you have to stop and think about where that field is being instantiated, it derails your train of thought.

As an added bonus, doing things this way also means that you can make an existing UpdateControls-based model into a serializable model just by changing its base class, and nothing else:

[DataContract]
public class FooModel : SerializableModel {
    private readonly Independent<bool> _active = new Independent<bool>();
    [DataMember]
    public bool Active { ... }

I like the way this code reads. All the UpdateControls-based stuff looks exactly like you’d expect. The only unusual thing is that you’re descending from SerializableModel, and that’s almost as declarative as the [DataContract] attribute.

One big caution: if you pass a default value to the Independent<T> constructor, that default won’t be used for deserialization. This isn’t a problem in the usual case, where you’re about to load that property’s value from storage. But if you’re reading an older stream that doesn’t contain that property, you might have to figure something out.

Without further ado, here’s the SerializableModel class. This was written for WinRT, but should also work in .NET 4.5. (If you’re using an older version of .NET, the Reflection APIs are totally different.)

[DataContract]
public class SerializableModel
{
    private IEnumerable<TypeInfo> Ancestry
    {
        get
        {
            for (var type = GetType(); type != null; type = type.GetTypeInfo().BaseType)
                yield return type.GetTypeInfo();
        }
    }

    private void CreateIndependentFields()
    {
        var independentFields =
            from type in Ancestry
            from field in type.DeclaredFields
            let fieldType = field.FieldType.GetTypeInfo()
            where fieldType.IsGenericType &&
                  fieldType.GetGenericTypeDefinition() == typeof(Independent<>)
            select field;

        foreach (var field in independentFields)
        {
            var instance = Activator.CreateInstance(field.FieldType);
            field.SetValue(this, instance);
        }
    }
    [OnDeserializing, UsedImplicitly]
    private void OnDeserializing(StreamingContext context)
    {
        CreateIndependentFields();
    }
}

I consider this code to be more of a useful technique than actual copyrighted intellectual property, so feel free to use the above code in any context you wish (no credit necessary). But I’d appreciate hearing about it if you find this useful.

There are no responses to “Making DataContractSerializer play nice with UpdateControls” yet.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Joe White's Blog copyright © 2004-2011. Portions of the site layout use Yahoo! YUI Reset, Fonts, and Grids.
Proudly powered by WordPress. Entries (RSS) and Comments (RSS). Privacy policy