views:

198

answers:

1

We have a huge client/server WinForms app that uses .NET remoting to pass DAOs between the layers, which has a few problems.

  1. All of the DAOs were defined to use fields instead of properties long before I got here, and you can't bind fields to controls.
  2. Adding fields or properties to a DAO changes the serialization format, requiring a dual client/server deployment, which is much more difficult for us than either a client or server deployment (we have to work around doctors' schedules to minimize downtime).

Using a simple, contrived, and imaginary example, would changing the object from this:

public class Employee
{
    public int ID;
    public string Name;
    public DateTime DateOfBirth;
}

to this:

public class Employee
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
}

change the serialization format, breaking compatibility with older clients?

+1  A: 

Important edit: this should be compatible and allow binding?

public class Employee
{
    private int id;
    private string name;
    private DateTime dateOfBirth;
    public int ID { get {return id;} set {id = value;} }
    public string Name { get {return name;} set {name = value;} }
    public DateTime DateOfBirth { get {return dateOfBirth;}
         set {dateOfBirth = value;} }
}

Certainly worth a try, no?

Yes, this will cause problems if client/server are out of sync.

.NET remoting uses BinaryFormatterm which (without a bespoke ISerializable implementation) uses the field names. Using automatic properties breaks the field names.

As long as you update client and server at the same time, it should work. Another option is to use name-independent serialization, such as protobuf-net. I can provide an example if you want (it supports ISerializable usage).

(by the way, adding properties should not affect BinaryFormatter, since it is field-based)


As requested, here's an example of using protobuf-net to control remoting serialization (taken directly from one of my unit tests); note that this will also be incompatible until both client and server agree, but should withstand changes after that (it is designed to be very extensible). Note that there are lots of ways of using it - either explicit member notation (like data-contracts) or implicit fields (like BinaryFormatter), etc (everything in between)... this is just one way of using it:

[Serializable, ProtoContract]
public sealed class ProtoFragment : ISerializable
{
    [ProtoMember(1, DataFormat=DataFormat.TwosComplement)]
    public int Foo { get; set; }
    [ProtoMember(2)]
    public float Bar { get; set; }

    public ProtoFragment() { }
    private ProtoFragment(
        SerializationInfo info, StreamingContext context)
    {
        Serializer.Merge(info, this);
    }
    void  ISerializable.GetObjectData(
        SerializationInfo info, StreamingContext context)
    {
        Serializer.Serialize(info, this);
    }
}

Here, the bottom 2 methods satisfy ISerializable, and simply pass execution to the protobuf-net engine. The [ProtoMember(...)] defines fields (with unique identification markers). As already stated, it can also infer these, but it is safer (less brittle) to be explicit.

Marc Gravell
It helps that you're the protobuf-net author ;)
Joel Coehoorn
Well, yes. But it is free, so this isn't marketing. The fact is the google-bods solved a lot of problems with their wire format. I'm happy to be able to offer those fixes available to the .NET user base (again, for free).
Marc Gravell
I'd love to see an example. Thanks for the quick response.
Chris Doggett
I'll copy one from my unit tests project... 2 secs...
Marc Gravell