6

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);
}
P a u l
  • 7,805
  • 15
  • 59
  • 92

2 Answers2

17

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!

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • RuntimeTypeModel.Default.InferTagFromNameDefault = true; seems to work thanks. – P a u l Nov 18 '11 at 13:04
  • 1
    @Paul just please note the emphasis in the above; that is **not** stable if members are added, since it is alphabetical. If you add `AardvarkCount`, everything will be off-by-one suddenly – Marc Gravell Nov 18 '11 at 13:44
1

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

Paul Farry
  • 4,730
  • 2
  • 35
  • 61