是否有一种高性能的方法来替换 .NET5 中的 BinaryFormatter?

问题描述 投票:0回答:4

在 .NET5 之前,我们通过这些代码序列化/反序列化字节/对象:

    private static byte[] StructToBytes<T>(T t)
    {
        using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, t);
            return ms.ToArray();
        }
    }

    private static T BytesToStruct<T>(byte[] bytes)
    {
        using (var memStream = new MemoryStream())
        {
            var binForm = new BinaryFormatter();
            memStream.Write(bytes, 0, bytes.Length);
            memStream.Seek(0, SeekOrigin.Begin);
            var obj = binForm.Deserialize(memStream);
            return (T)obj;
        }
    }

但是出于安全原因,BinaryFormatter 将被删除:

https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide

那么有没有一些简单但高性能的方法来替代 BinaryFormatter?

binaryformatter .net-5
4个回答
15
投票

在我最近从 .NET Core 3.1 迁移到 .NET 5 的项目中,我用 Protobuf-net 替换了 BinarySerializer 代码:https://github.com/protobuf-net/protobuf-net

代码几乎完全相同,该项目在 GitHub 上(目前)有 2200 万次下载和 3200 颗星,享有很高的声誉。它速度非常快,并且没有 BinarySerializer 周围的任何安全包袱。

这是我的 byte[] 序列化课程:

public static class Binary
{
    /// <summary>
    /// Convert an object to a Byte Array, using Protobuf.
    /// </summary>
    public static byte[] ObjectToByteArray(object obj)
    {
        if (obj == null)
            return null;

        using var stream = new MemoryStream();

        Serializer.Serialize(stream, obj);

        return stream.ToArray();
    }

    /// <summary>
    /// Convert a byte array to an Object of T, using Protobuf.
    /// </summary>
    public static T ByteArrayToObject<T>(byte[] arrBytes)
    {
        using var stream = new MemoryStream();

        // Ensure that our stream is at the beginning.
        stream.Write(arrBytes, 0, arrBytes.Length);
        stream.Seek(0, SeekOrigin.Begin);

        return Serializer.Deserialize<T>(stream);
    }
}

我确实必须向我序列化的类添加属性。它只用 [Serializable] 装饰,虽然我知道 Protobuf 可以使用很多常见的装饰,但那个没有用。来自 github 上的示例:

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

[ProtoContract]
class Address {
    [ProtoMember(1)]
    public string Line1 {get;set;}
    [ProtoMember(2)]
    public string Line2 {get;set;}
}

就我而言,我在 Redis 中缓存内容,效果很好。

也可以在您的 .csproject 文件中重新启用它:

<PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

...但这是个坏主意。 BinaryFormatter 是许多 .NET 历史漏洞的罪魁祸首,而且无法修复。它可能在未来的 .NET 版本中变得完全不可用,因此替换它是正确的做法。


7
投票

如果您使用的是 .NET Core 5 或更高版本,则可以像这样使用新的

System.Text.Json.JsonSerializer.Serialize
System.Text.Json.JsonSerializer.Deserialize

public static class Binary
{
    /// <summary>
    /// Convert an object to a Byte Array.
    /// </summary>
    public static byte[] ObjectToByteArray(object objData)
    {
        if (objData == null)
            return default;

       return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(objData, GetJsonSerializerOptions()));
    }

    /// <summary>
    /// Convert a byte array to an Object of T.
    /// </summary>
    public static T ByteArrayToObject<T>(byte[] byteArray)
    {
        if (byteArray == null || !byteArray.Any())          
            return default;
            
        return JsonSerializer.Deserialize<T>(byteArray, GetJsonSerializerOptions());
    }

    private static JsonSerializerOptions GetJsonSerializerOptions()
    {
        return new JsonSerializerOptions()
        {
            PropertyNamingPolicy = null,
            WriteIndented = true,
            AllowTrailingCommas = true,
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        };
    }
}

2
投票

虽然是旧线程,但它仍然相关,尤其是如果您发现自己处理在 Memcached(或 Redis,或本地或云中的二级存储)中存储 .NET 数据的代码。

BinaryFormatter
有OP中提到的安全问题,也有性能和尺寸问题。

一个很好的选择是 MessagePack 格式,更具体地说是 .NET 解决方案的 MessagePack NuGet 包

它是安全的、维护的、更快的、更小的。有关详细信息,请参阅基准

ZeroFormatter 似乎也是一个不错的选择。

在当今以云为中心的解决方案中,规模和容量对于降低成本非常重要,这些非常有用。


0
投票

在 .NET Core 5 中有一个使用它的选项:

只需添加

<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>

像这样的项目:

<PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

我相信它会起作用。

© www.soinside.com 2019 - 2024. All rights reserved.