If the existing session-state code uses BinaryFormatter
, then you can cheat by getting protobuf-net to act as an internal proxy for BinaryFormatter
, by implementing ISerializable
on your root object only:
[ProtoContract]
class SessionObject : ISerializable {
public SessionObject() { }
protected SessionObject(SerializationInfo info, StreamingContext context) {
Serializer.Merge(info, this);
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
Serializer.Serialize(info, this);
}
[ProtoMember(1)]
public string Foo { get; set; }
...
}
Notes:
- only the root object needs to do this; the any encapsulated objects will be handled automatically by protobuf-net
- it will still ad d a little type metadata for the outermost object, but not much
- you will need to decorate the members (and encapsulated types) accordingly (this is best done explicit per member; there is an implicit "figure it out yourself" mode, but this is brittle if you add new members)
- this will break existing state; changing the serialization mechanism is fundamentally a breaking change
If you want to ditch the type metadata from the root object, you would have to implement your own state provider (I think there is an example on MSDN);
- advantage: smaller output
- advantage: no need to implement
ISerializable
on the root object
- disadvantage: you need to maintain your own state provider ;p
(all the other points raised above still apply)
Note also that the effectiveness of protobuf-net here will depend a bit on what the data is that you are storing. It should be smaller, but if you have a lot of overwhelmingly large strings it won't be much smaller, as protobuf still uses UTF-8 for strings.
If you do have lots of strings, you might consider additionally using gzip - I wrote a state provider for my last employer that tried gzip, and stored whichever (original or gzip) was the smallest - obviously with a few checks, for example:
- don't gzip if it is smaller than [some value]
- short-circuit the gzip compression early if the gzip ever exceeds the original
The above can be used in combination with protobuf-net quite happily - and if you are writing a state-provider anyway you can drop the ISerializable
etc for maximum performance.
A final option, if you really want would be fore me to add a "compression mode" property to [ProtoContract(..., CompressionMode = ...)]
; which:
- would only apply for the
ISerializable
usage (for technical reasons, it doesn't make sense to change the primary layout, but this scenario would be fine)
- automatically applies gzip during serialization/deserialization of the above [perhaps with the same checks I mention above]
- would mean you don't need to add your own state provider
However, this is something I'd only really want to apply for "v2" (I'm being pretty brutal about bugfix only in v1, so that I can keep things sane).
Let me know if that would be of interest.