Custom Serialization and Remoting

by Mufaka 1/17/2008 8:22:00 PM

When you use .NET Remoting to communicate using custom objects between processes, you can suffer a performance penalty if you do not perform custom serialization on those objects.

Why? The default serialization is a generic implementation that includes all of the CLR type information for each object. This is needed to reconstruct the object on the receiving end of the remoting call.

This isn't a really big deal if you are only communicating single objects at a time and infrequently. This does become noticeable if you are returning custom collections that contain many objects or your application is really chatty.

Ok, so how do you improve the performance? Implement ISerializable on your objects and collections. It's a little tedious, but easy to do. Someday I may write an addin to do this work for me, but currently I use a code generator for my objects that includes this.

There are 3 things you need to do. In the example below, we are going to serialize the object as a byte[]. This serialization will be automatically called by the Remoting formatter when sending the object over the wire.

1. Designate the class as ISerializable

public class Issue : ISerializable

2. Implement the GetObjectData method defined by ISerializable.

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    MemoryStream ms = new MemoryStream();
    BinaryWriter bw = new BinaryWriter(ms);

    // if any members are nullable, you will need to check for that before writing
    bw.Write(_iD);
    bw.Write(_createdUserID);
    bw.Write(_assignedToUserID);
    bw.Write(_title);
    bw.Write(_description);
    bw.Write(_releaseNote);
    bw.Write(_issueStatusID);
    bw.Write(_issuePriorityID);
    bw.Write(_insertDate.Ticks);
    bw.Close();

    info.AddValue("b", ms.ToArray());
}

3. Implement a constructor that will receive this serialized form of your object.

public Issue(SerializationInfo info, StreamingContext context)
{
    MemoryStream ms = new MemoryStream((byte[])info.GetValue("b", typeof(byte[])));
    BinaryReader br = new BinaryReader(ms);

    _iD = br.ReadInt32();
    _createdUserID = br.ReadInt32();
    _assignedToUserID = br.ReadInt32();
    _title = br.ReadString();
    _description = br.ReadString();
    _releaseNote = br.ReadString();
    _issueStatusID = br.ReadInt32();
    _issuePriorityID = br.ReadInt32();
    _insertDate = new DateTime(br.ReadInt64());
}

And that is it. Your custom object can now be sent over the wire with the minimal amount of information needed to reconstruct it on the other end.

What about collections? You do the same thing, but for every object in the collection.

Designate the collection as ISerializable

public class IssueCollection : CollectionBase, ISerializable

Build the byte[] using all of the objects in the collection.

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    MemoryStream ms = new MemoryStream();
    BinaryWriter bw = new BinaryWriter(ms);

    foreach (Issue obj in this)
    {
        bw.Write(obj.ID);
        bw.Write(obj.CreatedUserID);
        bw.Write(obj.AssignedToUserID);
        bw.Write(obj.Title);
        bw.Write(obj.Description);
        bw.Write(obj.ReleaseNote);
        bw.Write(obj.IssueStatusID);
        bw.Write(obj.IssuePriorityID);
        bw.Write(obj.InsertDate.Ticks);
    }
    info.AddValue("b", ms.ToArray());
}

Getting the collection of objects from the collection is done by looping through the array and reading the bytes into a new instance of your object.

public IssueCollection(SerializationInfo info, StreamingContext context)
{
    MemoryStream ms = new MemoryStream((byte[])info.GetValue("b", typeof(byte[])));
    BinaryReader br = new BinaryReader(ms);

    Int64 length = ms.Length;

    while (br.BaseStream.Position < length)
    {
        Issue obj = new Issue();
        obj.ID = br.ReadInt32();
        obj.CreatedUserID = br.ReadInt32();
        obj.AssignedToUserID = br.ReadInt32();
        obj.Title = br.ReadString();
        obj.Description = br.ReadString();
        obj.ReleaseNote = br.ReadString();
        obj.IssueStatusID = br.ReadInt32();
        obj.IssuePriorityID = br.ReadInt32();
        obj.InsertDate = new DateTime(br.ReadInt64());
        Add(obj);
    }
}

The larger the collection of data you are sending across the wire, the more the performance of custom serialization is realized.

Powered by BlogEngine.NET 1.3.1.0
Theme by Mads Kristensen

About the author

Name of author Mufaka
I am a software developer currently working on Healthcare solutions using Microsoft technologies.

E-mail me Send mail

Calendar

<<  July 2008  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar

Pages

    Recent comments

    Authors

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2008

    Sign in