Introduction
With the release of .NET 9 Core Framework, . BinaryFormatter is now not included in the .NET 9 runtime.
There is no drop-in replacement for BinaryFormatter, but there are several serializers recommended for serializing .NET types. Regardless of which serializer you choose, changes will be needed for integration with the new serializer. During these migrations, it's important to consider the trade-offs between coercing the new serializer to handle existing types with as few changes as possible vs. refactoring types to enable idiomatic serialization with the chosen serializer. Once a serializer is chosen, its documentation should be studied for best practices.
(Above is from Microsoft documentation)
It is recommended that before performing a migration to ensure there is a working copy of a project in source control repository such as GitHub. Also, in the working copy have a test project that during the migration new test methods will be needed.
Learn about migration options from the list of serializer by way of code samples.
- System.Text.Json
- XML using DataContractSerializer
- Binary using MessagePack
- Binary using protobuf-net
Important code sample notes
Each code sample are void of exception handling as all work in done in the project’s debug folder which a developer has permissions. For an actual application use assertion, try-catch blocks and optionally logging runtime errors to a physical log file using a provider such as
Samples
All code samples use mocked up data from
JSON using System.Text.Json
Using System.Text.Json is straight forward, call the Serialize method to serialize data and Deserialize with the type.
In the following examples the following private variable represents the file to read and write too.
private static string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "person1.json");
The following models are used.
public class Person1 : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateOnly BirthDate { get; set; }
public string SSN { get; set; }
public Address Address { get; set; }
}
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Note
ProtoContract on Address is ignored for this sample.
public static JsonSerializerOptions Indented => new() { WriteIndented = true };
public static void SerializePeople()
{
List<Person1> people = MockedData.GetPersons1();
var json = JsonSerializer.Serialize(people, Indented);
File.WriteAllText(fileName, json);
}
public static void DeserializePeople()
{
var people = JsonSerializer.Deserialize<List<Person1>>(
File.ReadAllText(fileName));
}
XML using DataContractSerializer
class. So if this is your option copy DataContractSerializerHelpers into a project or if there are several projects that need migration, place the class in a new class project and reference the class project.
internal class DataContractSerializerOperations
{
private static string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "person1.data");
public static void SerializePeople()
{
List<Person2> people = MockedData.GetPersons2();
var text = Serialize(people);
File.WriteAllText(fileName,text);
var list = Deserialize(text, typeof(List<Person2>)) as List<Person2>;
}
public static string Serialize(object obj)
{
using MemoryStream memoryStream = new();
DataContractSerializer serializer = new(obj.GetType());
serializer.WriteObject(memoryStream, obj);
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
public static object Deserialize(string xml, Type toType)
{
using MemoryStream memoryStream = new(Encoding.UTF8.GetBytes(xml));
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(memoryStream, Encoding.UTF8,
new XmlDictionaryReaderQuotas(), null);
DataContractSerializer serializer = new DataContractSerializer(toType);
return serializer.ReadObject(reader);
}
}
MessagePack
The extremely fast MessagePack serializer for C#.
MessagePack is the most configurable, performant and capable of all available migration paths. In the code samples provided are basic.
One nice feature is the ability to configure a class to use MessagePack when a developer does not have access to the class source code but there is performance penalties as described in their documentation.
MessagePack NuGet package contains analyzers and source generator for MessagePack for C#. Verify rules for [MessagePackObject] and code fix for [Key].
is a contract based serializer for .NET code, that happens to write data in the "protocol buffers" serialization format engineered by Google.
The protobuf-net library is easy to use, decorate a class and properties with attributes followed by using Serializer.Serialize to serialize data and Serializer.Deserialize to deserialize data.
Class decelerated to include all properties for serializing data,
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Person : IPerson
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateOnly BirthDate { get; set; }
public string SSN { get; set; }
public Address Address { get; set; }
}
Sample operations
using BinaryFormatterAlternate.Models;
using static BinaryFormatterAlternate.Classes.SpectreConsoleHelpers;
namespace BinaryFormatterAlternate.Classes;
internal class ProtobufOperations
{
private static string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "people.bin");
public static void SerializePeople()
{
List<Person> people = MockedData.GetPersons();
using var file = File.Create(fileName);
Serializer.Serialize(file, people);
}
public static void DeserializePeople()
{
using var file = File.OpenRead(fileName);
var people = Serializer.Deserialize<List<Person>>(file);
AnsiConsole.MarkupLine($"{BeautifyPersonDump(people.Dump())}");
}
}
See also
- Migrate (ResX)
- Use the compatibility package
Summary
Several external and internal libraries have been presented to migrate away from using BinaryFormatter class using basic syntax to allow developers to select a path that fits their needs.
SOCIAL SHARE CARD GENERATOR