为什么.NET 9.0 强烈建议不要使用 BinaryFormatter,并且移除了相关支持

在这里插入图片描述

1. 引言

在 .NET 的早期版本中,BinaryFormatter 是一个广泛使用的工具,用于将对象序列化为二进制格式,以便在网络上传输或持久化存储。然而,随着 .NET 框架的发展和安全性需求的提升,BinaryFormatter 的一些固有问题逐渐显现,最终导致在 .NET 9.0 中被彻底移除。那么,BinaryFormatter 是什么?为什么它会被移除?我们又该如何应对?本文将深入探讨这些问题,并提供一些替代方案。
在这里插入图片描述

2. 什么是 BinaryFormatter?

BinaryFormatter 是 .NET 框架中的一个序列化工具,它能够将对象及其状态转换为二进制流。这些二进制数据可以被存储到文件中、通过网络传输,或者在应用程序的不同部分之间传递。其基本工作原理如下:

  1. 序列化:将对象转换为二进制格式的过程。这个过程遍历对象的成员,并将其数据转换为字节流。
  2. 反序列化:将二进制数据恢复为原始对象的过程。反序列化通过读取二进制流,恢复对象的状态。

BinaryFormatter 的使用相对简单,示例如下:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };

        // 序列化
        var formatter = new BinaryFormatter();
        using (var stream = new FileStream("person.dat", FileMode.Create, FileAccess.Write))
        {
            formatter.Serialize(stream, person);
        }

        // 反序列化
        using (var stream = new FileStream("person.dat", FileMode.Open, FileAccess.Read))
        {
            var deserializedPerson = (Person)formatter.Deserialize(stream);
            Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
        }
    }
}

在这个例子中,BinaryFormatterPerson 对象序列化为二进制格式,并将其保存到文件中。随后,它通过反序列化从二进制文件中恢复对象。

3. 为什么移除了 BinaryFormatter 的支持?

官方给出的解释是,存在相关的安全风险,那么到底是哪些风险呢?
在这里插入图片描述

BinaryFormatter 的移除主要出于以下几个原因:

  1. 安全性问题BinaryFormatter 的反序列化功能存在安全漏洞,容易受到反序列化攻击。这些攻击可能导致远程代码执行,使应用程序暴露在风险之中。

  2. 跨平台兼容性差BinaryFormatter 的二进制格式在不同平台之间的兼容性不佳,这与 .NET 的跨平台战略相冲突。

  3. 维护成本高:随着时间的推移,维护 BinaryFormatter 的安全性和稳定性变得越来越困难。移除它可以减少框架的维护负担。为了修复 BinaryFormatter 的安全漏洞,需要持续的维护工作,这对于一个已经不再积极发展的 API 来说是一种负担。

  4. 性能问题: BinaryFormatter 的性能并不总是最优的。它的序列化和反序列化过程较为复杂,导致性能不如其他现代序列化技术。

  5. 现代化替代方案:随着 .NET 的发展,出现了许多更安全、更高效的序列化工具,提供了更好的性能和功能。如 JSON.NET、System.Text.Json 和 MessagePack,它们提供了更好的性能和更高的安全性。

4. 替代方案

随着 BinaryFormatter 的移除,可以选择以下替代方案来进行序列化和反序列化:

4.1. System.Text.Json

System.Text.Json 是 .NET Core 3.0 引入的一个高性能、轻量级的 JSON 序列化器,它支持 JSON 文档、JSON 数组和 JSON 对象的解析和序列化,并且具有很好的性能。适用于大多数场景。它提供了快速、高效、跨平台的序列化和反序列化功能。

适用场景:
  • 适合大多数需要 JSON 序列化的应用程序,尤其是 Web API 和配置文件处理。
优点
  • 安全性高,避免了反序列化攻击的风险。
  • 高性能,针对现代硬件进行了优化。
  • 内置支持,开箱即用。
缺点:
  • 对复杂对象图的支持有限,不支持循环引用。
示例代码
using System;
using System.Text.Json;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };

        // 序列化
        string json = JsonSerializer.Serialize(person);
        Console.WriteLine($"Serialized JSON: {json}");

        // 反序列化
        var deserializedPerson = JsonSerializer.Deserialize<Person>(json);
        Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
    }
}

4.2. XmlSerializer

XmlSerializer 是处理 XML 序列化的主要工具,适合需要与 XML 数据格式兼容的场景。

适用场景:
  • 适用于需要与 XML 数据格式兼容的系统,如跨平台数据交换或与遗留系统集成。
优点
  • 适合与其他使用 XML 的系统集成。
  • 可读性强,便于调试。
缺点:
  • 序列化复杂对象较慢,不支持私有成员的序列化。
示例代码
using System;
using System.IO;
using System.Xml.Serialization;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };

        // 序列化
        var serializer = new XmlSerializer(typeof(Person));
        using (var stream = new StringWriter())
        {
            serializer.Serialize(stream, person);
            string xml = stream.ToString();
            Console.WriteLine($"Serialized XML: {xml}");

            // 反序列化
            using (var reader = new StringReader(xml))
            {
                var deserializedPerson = (Person)serializer.Deserialize(reader);
                Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
            }
        }
    }
}

4.3. DataContractSerializer

DataContractSerializer 是一个强大的序列化工具,适合处理复杂对象图。它支持 XML 和二进制格式。

适用场景:
  • 适合处理复杂对象图,尤其是在 WCF 服务中使用。
优点
  • 支持复杂类型的序列化。
  • 可与 WCF 等技术集成。
缺点:
  • XML 格式较大,性能不如二进制格式。
示例代码
using System;
using System.IO;
using System.Runtime.Serialization;

[DataContract]
public class Person
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };

        // 序列化
        var serializer = new DataContractSerializer(typeof(Person));
        using (var stream = new MemoryStream())
        {
            serializer.WriteObject(stream, person);
            stream.Position = 0;

            using (var reader = new StreamReader(stream))
            {
                string xml = reader.ReadToEnd();
                Console.WriteLine($"Serialized Data: {xml}");
            }

            // 反序列化
            stream.Position = 0;
            var deserializedPerson = (Person)serializer.ReadObject(stream);
            Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
        }
    }
}

4.4. Protocol Buffers(protobuf-net)

Protocol Buffers 是一种高效的二进制序列化方案,特别适合跨平台和大规模数据的处理。

适用场景:
  • 适合需要高效二进制格式的跨平台和大规模数据处理,常用于微服务通信和移动开发。
优点
  • 高效的二进制格式,适合大规模数据处理。
  • 支持多种语言和平台。
缺点:
  • 需要定义 .proto 文件,学习曲线较高。
示例代码
using System;
using System.IO;
using ProtoBuf;

[ProtoContract]
public class Person
{
    [ProtoMember(1)]
    public string Name { get; set; }
    [ProtoMember(2)]
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };

        // 序列化
        using (var stream = new MemoryStream())
        {
            Serializer.Serialize(stream, person);
            byte[] data = stream.ToArray();
            Console.WriteLine($"Serialized Data: {BitConverter.ToString(data)}");

            // 反序列化
            using (var memoryStream = new MemoryStream(data))
            {
                var deserializedPerson = Serializer.Deserialize<Person>(memoryStream);
                Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
            }
        }
    }
}

4.5. MessagePack

MessagePack 是一种高效的二进制序列化格式,提供比 JSON 更高的性能,并且支持强类型对象的序列化和反序列化。MessagePack 支持多种数据类型,并且可以轻松集成到 .NET 应用程序中。

适用场景:
  • 适用于对性能要求较高的应用,如游戏开发、文件存储、分布式系统。
优点
  • 高效的二进制格式,文件体积小,性能高。
  • 支持复杂的对象图序列化。
  • 序列化结果兼容不同语言和平台。
缺点:
  • 对调试不太友好,序列化结果不易阅读。
示例代码
using System;
using MessagePack;

[MessagePackObject]
public class Person
{
    [Key(0)]
    public string Name { get; set; }
    [Key(1)]
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var person = new Person { Name = "John", Age = 30 };
        // 序列化
        byte[] data = MessagePackSerializer.Serialize(person);
        Console.WriteLine($"Serialized Data: {BitConverter.ToString(data)}");
        // 反序列化
        var deserializedPerson = MessagePackSerializer.Deserialize<Person>(data);
        Console.WriteLine($"Name: {deserializedPerson.Name}, Age: {deserializedPerson.Age}");
    }
}

5. 总结

BinaryFormatter 在 .NET 中的移除标志着一个时代的结束,同时也开启了更安全、更高效的序列化替代方案的新时代。无论是处理 JSON、XML、二进制数据,还是需要跨平台的兼容性,都可以在 .NET 中找到合适的工具来满足你的需求。选择合适的序列化方案,不仅可以提升应用程序的安全性和性能,还能更好地与现代开发实践接轨。

6.参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dotnet研习社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值