Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is DataMember(Order=n) annotation required for protobuf-net v2?

Tags:

protobuf-net

Simple experiment: I created an entity model from Northwind, and find that the generated classes don't work for protobuf-net v2 without adding the Order property. Is there a way to get the entity code generator to add Order, or is there a way to get protobuf-net to work without Order?

I have to change

[DataMemberAttribute()]

to

[DataMemberAttribute(Order=1)], etc.

NorthwindEntities e = new NorthwindEntities();

using(var file = File.Create("customers.bin"))
{
    Serializer.Serialize(file, e.Customers);
}
like image 354
P a u l Avatar asked Nov 17 '11 22:11

P a u l


2 Answers

What is required is that it has a way to resolve members to numeric keys. This can take the form of inline attributes - for example, it allows [DataContract]/[DataMember(Order=key)], [XmlType]/[XmlElement(Order=key)], or [ProtoContract]/[ProtoMember(key)].

There are also options via [DataContract] to infer the contract alphabetically, but this is only safe if your contract type is not going to change in the future; to do this, add:

[ProtoContract(InferTagFromName = true)]

to the type (perhaps in a partial, see below). This applies directly to the scenario you present, where [DataMember] indicates the members, but there is no defined Order. Personally I prefer explicit layouts, for stability.

Another option doesn't even need hints like [DataMember]; you can ask it to apply either BinaryFormatter rules (all fields, public or private), or XmlSerializer rules (public members, properties or fields); again, though, this is very unstable if your type changes!

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]

But; another common scenario is that you have types coming from a generator, that you can't conveniently edit, since any edits would get lost at re-generation; for that scenario, partial classes can be helpful. You can't add attributes to members via attributes, but [ProtoPartialMember] can help here. For example, in a separate code file:

[ProtoContract]
[ProtoPartialMember(key, memberName)]
[ProtoPartialMember(anotherKey, anotherMemberName)]
...
public partial class Order {}

Sometimes, you have no access whatsoever to the type, so adding attributes of any kind is not an option. If your scenario is as you describe ([DataContract/[DataMember], noOrder`), then a lazy option is to enable this globally:

Serializer.GlobalOptions.InferTagFromName = true;

or in v2:

RuntimeTypeModel.Default.InferTagFromNameDefault = true;

For more complex scenarios, v2 has a new MetaType model devoted to this, where you can configure the layout at runtime:

RuntimeTypeModel.Default.Add(typeof(Order), false)
            .Add(key, memberName).Add(anotherKey, anotherMemberName);

or if your keys are 1, 2, 3, ... then just:

   RuntimeTypeModel.Default.Add(typeof(Order), false)
            .Add(memberName, anotherMemberName, ...);

(there are a myriad of options on the MetaType to control all aspects of the serialization)

I think that covers most of the options here!

like image 134
Marc Gravell Avatar answered Nov 12 '22 04:11

Marc Gravell


I've only just begun my dive into ProtoBuf, and therefore haven't really looked at the previous version, but I've been using looking at the stream that is generated it's ordered as expected.

<protocontract()>
Public Class Peer
   <ProtoMember(1)>
    Public Property PacketNumber As Long
    <ProtoMember(2)>
    Public Property DateCreated As DateTime
    <ProtoMember(3)>
    Public Property Data As String 
    <ProtoMember(4)>
    Public Property OriginatingTerminal As Integer
end class

Hope this helps

like image 20
Paul Farry Avatar answered Nov 12 '22 05:11

Paul Farry