Migrate to protobuf-net (binary)
The protobuf-net library is a contract-based serializer for .NET that uses the binary Protocol Buffers serialization format. The API follows typical .NET patterns and is broadly comparable to XmlSerializer
and DataContractSerializer
.
Some behaviors and features of protobuf-net will be notable during migrations from BinaryFormatter, and many scenarios require applying attributes to members.
- By default, both public and non-public types are serializable, with the serializer expecting a parameterless constructor.
- protobuf-net requires each serializable type to be annotated with
[ProtoContract]
attribute; this attribute can optionally specify theSkipConstructor = true
property, which removes the need for any particular constructor. - Every serializable non-static field and a property needs to be annotated with
[ProtoMember(int identifier)]
attribute. The member names aren't encoded in the data. Instead, the users must pick a positive integer to identify each member which must be unique within that type. - Inheritance must be explicitly declared via
[ProtoInclude(...)]
attribute on each type with known subtypes. - Read-only fields are supported by default.
- Alternatively, some non-attributed tuple-like types are recognized by constructor pattern; a type with a constructor that has parameters that match (by name) all of the declared public members will be interpreted as a tuple, and the parameter order will be used to infer the identifier for that member.
- The use of the
protobuf-net.BuildTools
design-time package is highly recommended; this offers compile-time warnings of common errors.
Step by step migration
- Find all the usages of
BinaryFormatter
. - Ensure that the serialization code paths are covered with tests, so you can verify your changes and avoid introducing bugs.
- Install
protobuf-net
package (and optionallyprotobuf-net.BuildTools
). - Find all the types that are being serialized with
BinaryFormatter
. - For types that you can modify:
- Annotate with
[ProtoContract]
attribute all types that are marked with[Serializable]
or implement theISerializable
interface. If these types are not exposed to other apps (example: you are writing a library) that may use different serializers likeDataContractSerializer
, you can remove the[Serializable]
andISerializable
annotations. - For derived types, apply
[ProtoInclude(...)]
to their base types (see the example below). - For every type that declares any constructor that accepts parameters, add a parameterless constructor, or specify
SkipConstructor = true
on the[ProtoContract]
attribute. Leave a comment that explains the protobuf-net requirement (so nobody removes it by accident). - Mark all the members (fields and properties) that you wish to serialize with
[ProtoMember(int identifier)]
. All identifiers must be unique within a single type, but the same numbers can be re-used in sub-types if inheritance is enabled.
- Annotate with
- For types that you can't modify:
- For types provided by the .NET itself, you can use
ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(Type type)
API to check if they are natively supported by protobuf-net. - You can create dedicated data transfer objects (DTO) and map them accordingly (you could use implicit cast operator for that).
- Use the
RuntimeTypeModel
API to define everything that the attributes allow for.
- For types provided by the .NET itself, you can use
- Replace the usage of
BinaryFormatter
withProtoBuf.Serializer
.
-[Serializable]
+[ProtoContract]
+[ProtoInclude(2, typeof(Point2D))]
public class Point1D
{
+ [ProtoMember(1)]
public int X { get; set; }
}
-[Serializable]
+[ProtoContract]
public class Point2D : Point1D
{
+ [ProtoMember(2)]
public int Y { get; set; }
}
Tee yhteistyötä kanssamme GitHubissa
Tämän sisällön lähde on GitHubissa, jossa voit myös luoda ja tarkastella ongelmia ja pull-pyyntöjä. Katso lisätietoja osallistujan oppaasta.