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);
}
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], no
Order`), 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!
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With