Using protobuf-net to serialize objects without hassle

Serialization with protobuf-net

You are looking at revision 14 of this page, which may be out of date. View the latest version.  

protobuf-net is an open source .net implementation of Google's protocol buffer binary serialization format.

Consider the following classes, I have included a sub-class to make it slightly more than a non-trivial example

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime DateOfBirth { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Number { get; set; }
    public string StreetName { get; set; }
}

public class ExtendedAddress : Address
{
    public string BuildingName { get; set; }
}

With v2 of protobuf-net you can build a serializer on the fly which means you don't have to decorate the classes with attributes:

var protobufModel = ProtoBuf.Meta.TypeModel.Create();
AddTypeToModel<Person>(protobufModel);
AddTypeToModel<Address>(protobufModel).AddSubType(500, typeof(ExtendedAddress));
AddTypeToModel<ExtendedAddress>(protobufModel);

private MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{            
    var properties = typeof(T).GetProperties().Select(p => p.Name).ToArray();
    return typeModel.Add(typeof(T), true).Add(properties);            
}

While this method is effective it is considered brittle if the class changes. What would happen if we added a property Lot property to the Address class?
This would break the backwards compatibility of any previously serialized data as protobuf-net is assigning ids to each serialized field.

If we added a new property Suburb which is alphabetically after StreetName then everything would (luckily) work.

The moral of the story is only use this method if your class isn't going to change (sure!) or you dont care about backwards compatibility.

Instead, decorate your classes:

public class Person
{
    [ProtoMember(1)]
    public string Name { get; set; }
    [ProtoMember(2)]
    public int Age { get; set; }
    [ProtoMember(3)]
    public DateTime DateOfBirth { get; set; }        
    [ProtoMember(4)]        
    public Address Address { get; set; }
}

[ProtoInclude(500, typeof(ExtendedAddress))]
public class Address
{
    [ProtoMember(1)]
    public string Number { get; set; }
    [ProtoMember(2)]
    public string StreetName { get; set; }
}

public class ExtendedAddress : Address
{
    [ProtoMember(1)]
    public string BuildingName { get; set; }
}

protobuf-net also respects DataContract and DataMember attributes in the System.Runtime.Serialization namespace if you want to use them instead or if you class is attributed already.

Posted by: Wallace Turner
Last revised: 03 Nov, 2011 03:05 PM History
You are looking at revision 14 of this page, which may be out of date. View the latest version.

Comments

No comments yet. Be the first!

No new comments are allowed on this post.