2

I have a server-client application in which I can modify both codebases. The client communicates with the server through numerous web services and I share some of the classes defined on the server side through Web Reference system. On the wire the data is sent using XML (SOAP). Also, I save some of the data on the disk using XmlSerializer.

Due to rising performance issues, I want to migrate to a more sophisticated serializer with my eyes on Protocol Buffers and protobuf-net. I currently use protobuf-net v2 (r480, .NET 3.5)

The problem I seem to have is that classes shared through Web Reference system do not retain custom class/member attributes like ProtoContract and ProtoMember.
(But the serializer system does not throw the usual System.InvalidOperationException: Type is not expected, and no contract can be inferred, leaving me with an empty stream. Is it because the class generated on the client side is marked as partial?)

Example, server side:

[ProtoContract]
public class CommentStruct
{
    [ProtoMember(1)] public int id;
    [ProtoMember(2)] public DateTime time;
    [ProtoMember(3)] public string comment;
    [ProtoMember(4)] public int session;
}

Client side (generated code):

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://example.org")]
public partial class CommentStruct {
    private int idField;
    private System.DateTime timeField;
    private string commentField;
    private int sessionField;

    /// <remarks/>
    public int id {
        get {
            return this.idField;
        }
        set {
            this.idField = value;
        }
    }
    [...]

I managed to get around this issue using ProtoPartialMember in an extra class file on the client side:

[ProtoContract,
ProtoPartialMember(1, "id"),
ProtoPartialMember(2, "time"),
ProtoPartialMember(3, "comment"),
ProtoPartialMember(4, "session")]
public partial class CommentStruct
{
}

The main concern here is: can I do this in a different way to avoid code duplication?
The other is: will I miss out on some of the protobuf-net goodies like inheritance support?

I have found some information about protobuf-net Visual Studio add-in. But as Marc Gravell has decribed it as an 'afterthought', I am reluctant to use it. Moreover, some of my co-developers are using VS Express editions that do not support add-ins.

Edit: What I meant as my main duplication concern is having to specify the class members and protobuf-net attributes twice - in a class definition on the server side and in partial class attributes on the client side.

mczers
  • 257
  • 2
  • 8

1 Answers1

1

As a minor point of terminology, I would avoid the word "shared" here, as "shared" typically means: as a library (which would work).

The reason it doesn't throw an error is not related to partial; it is simply that protobuf-net is moderately happy to use the attributes of other libraries... within reason. For example, it will work with [XmlType] / [XmlElement(Order=n)] and with [DataContract] / [DataMember(Order=n)]. However, the code generated from the WSDL here does not include Order=n, so it doesn't see those as members needing to be serialized (it really needs the number).

The [ProtoPartialMember(...)] usage (as you mention) is one way around this. It doesn't restrict you from other protobuf-net usage. [ProtoInclude(...)] would still work (since you mention inheritance). Indeed, everything in protobuf-net can also be configured entirely at runtime, with zero attributes (via RuntimeTypeMode). Re duplication: I can't see anything duplicated except the class name. Arguably, [ProtoInclude(...)] is a bit of a duplication with [XmlInclude(...)], but not much.

I'm happy to believe I used the phrase in passing, but I'm not sure "afterthought" is really the main way I describe the add-in usage. To clarify: protobuf-net is primarily intended to fit the common .NET idiom of code-first (perhaps with attributes), rather than generating from a tool. It still works from either.

Of course, perhaps the easiest-of-all option, when available, is to simply share the .dll or the .cs. This works effortlessly with WCF / DataContractSerializer, but I'm not sure that the older "web reference" web-services love this very much. Of course, there also isn't plug-in support for using protobuf-net as part of an older-style "web reference" ("asmx"), so you probably already need to change some things there...

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • What I meant as my main duplication concern is having to specify the class members and protobuf-net attributes twice - in a class definition on the server side and in partial class attributes on the client side. Only now I found that the source for this 'afterthought' quotation is three years old: [link](http://stackoverflow.com/questions/1334659/how-do-i-generate-a-proto-file-from-a-c-sharp-class-decorated-with-attributes). I am sorry for digging up thread this old. – mczers Jul 11 '12 at 10:47