C#使用BinaryFormatter序列化类包含调用程序集信息导致反序列化失败如何解决
问题原因
你遇到的问题是BinaryFormatter的原生设计导致的:该序列化器默认会将被序列化对象的完整类型元数据(包含所属程序集名称、版本号、公钥Token等信息)写入序列化结果中,反序列化时会严格校验这些元数据是否与本地加载的类型完全匹配,因此跨程序集反序列化时就会抛出找不到对应程序集的异常。
解决方案
方案1:更换更安全的跨兼容序列化器(最推荐)
微软官方已经将BinaryFormatter标记为不安全API,生产环境不建议使用。你可以替换为以下不绑定程序集信息的序列化方案:
- JSON序列化:使用
System.Text.Json或Newtonsoft.Json,默认只序列化对象的字段/属性数据,不包含程序集信息,跨程序集、跨平台都可以正常反序列化 - 二进制序列化可选Protobuf(Google推出的高性能二进制序列化方案),兼容性和安全性都远高于BinaryFormatter
用System.Text.Json实现序列化的代码示例:
// 序列化 byte[] s = JsonSerializer.SerializeToUtf8Bytes(c); File.WriteAllBytes(@"C:\Temp\test.txt", s); // 反序列化 byte[] data = File.ReadAllBytes(@"C:\Temp\test.txt"); MyClass c = JsonSerializer.Deserialize<MyClass>(data);
方案2:将实体类抽离为共享类库
如果必须保留BinaryFormatter的使用,可以把MyClass这类需要序列化的实体类单独放到一个独立的类库项目中,所有需要做序列化、反序列化的项目都引用同一个该类库,这样两端的类型元数据完全一致,就不会出现程序集匹配失败的问题。
方案3:自定义序列化绑定器(临时兼容用)
如果无法调整项目结构,可以在反序列化端自定义SerializationBinder,手动映射类型,绕过默认的程序集校验逻辑:
首先实现自定义绑定器:
public class CustomSerializationBinder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { // 匹配到MyClass类型时直接返回当前程序集的MyClass类型 if (typeName == "CoolNamespace.MyClass") { return typeof(MyClass); } // 其他类型走默认匹配逻辑 return Type.GetType($"{typeName}, {assemblyName}"); } }
反序列化时给BinaryFormatter指定绑定器即可:
public static object Deserialize(byte[] data) { if (data == null) throw new ArgumentNullException(nameof(data)); using (MemoryStream memoryStream = new MemoryStream(data)) { BinaryFormatter formatter = new BinaryFormatter(); // 指定自定义绑定器 formatter.Binder = new CustomSerializationBinder(); return formatter.Deserialize(memoryStream); } }
注意:该方案仅适合临时兼容旧数据,BinaryFormatter存在远程代码执行的安全风险,反序列化不可信来源的数据时可能被攻击者利用,生产环境强烈建议更换序列化方案。
内容的提问来源于stack exchange,提问作者Buda Gavril
相关产品推荐
相关产品推荐

