简体   繁体   中英

How to use protobuf-net with classes generated through ASP.NET Web Reference while avoiding code duplication?

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.

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...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM