.net - .netcore 中的 BinaryFormatter
问题描述
.NET framework 和 .NET core 2.2 中的 BinaryFormatter 兼容性问题
我们byte[]
在 .NET 框架 4.0 类库(多个项目的通用库)中使用 BinaryFormatter 转换为 DataSet 的现有代码。现在我们添加了一个新的 asp.net core 2.2 项目并尝试使用相同的现有库,幸运的是我们解决了所有 dll 问题但无法调用 BinaryFormatter Deserialize 方法。
下面是通用代码:
BinaryFormatter oBinaryFormatter = new BinaryFormatter();
using (MemoryStream oMemoryStream = new MemoryStream())
{
//Deserialize the byte array into a DataSet and return it to the caller
oMemoryStream.Write(abData, 0, abData.Length);
oMemoryStream.Position = 0;
return (T)(oBinaryFormatter.Deserialize(oMemoryStream));
}
Inner Exception:
Type 'System.String' is not deserializable.
Source:
System.Private.CoreLib
Stack Trace:
at System.UnitySerializationHolder.GetRealObject(StreamingContext context)
at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder)
at System.Runtime.Serialization.ObjectManager.DoFixups()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(BinaryParser serParser, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, Boolean check)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at System.Data.DataSet.DeserializeDataSetSchema(SerializationInfo info, StreamingContext context, SerializationFormat remotingFormat, SchemaSerializationMode schemaSerializationMode)
at System.Data.DataSet..ctor(SerializationInfo info, StreamingContext context, Boolean ConstructSchema)
at System.Data.DataSet..ctor(SerializationInfo info, StreamingContext context)
解决方案
我无法重现此代码的问题:
var ds=new DataSet();
var table=new DataTable("Moo");
table.Columns.Add("Field1",typeof(string));
table.Columns.Add("Field2",typeof(int));
table.Rows.Add("Value1",1);
ds.Tables.Add(table);
ds.AcceptChanges();
var bf = new BinaryFormatter();
using (var stream=File.OpenWrite("test.bin"))
{
bf.Serialize(stream,ds);
}
using (var stream2=File.OpenRead("test.bin"))
{
var ds2=(DataSet)bf.Deserialize(stream2);
Debug.Assert(ds.Tables[0].TableName==ds2.Tables[0].TableName);
Debug.Assert(ds.Tables[0].Rows.Count==ds2.Tables[0].Rows.Count);
Debug.Assert((string)ds2.Tables[0].Rows[0]["Field1"]=="Value1");
Debug.Assert((int)ds2.Tables[0].Rows[0]["Field2"]==1);
}
查看生成的文件显示包含数据集的模式和 XML 以及类型 metadata ,使其比单独的 XML 文件更详细:
NSystem.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Data.DataSet DataSet.RemotingVersion XmlSchemaXmlDiffGramSystem.Version <?xml version="1.0" encoding="utf-16"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Moo">
<xs:complexType>
<xs:sequence>
<xs:element name="Field1" type="xs:string" msdata:targetNamespace="" minOccurs="0" />
<xs:element name="Field2" type="xs:int" msdata:targetNamespace="" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema> ‚<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet><Moo diffgr:id="Moo1" msdata:rowOrder="0"><Field1>Value1</Field1><Field2>1</Field2></Moo></NewDataSet></diffgr:diffgram> System.Version _Major_Minor_Build _Revision sion
那是1.3KB来保存99 个字节的文本。使用 GZipStream 编写相同的内容会产生 82 个字节:
using(var gs=new GZipStream(File.OpenWrite("text.gz"),CompressionMode.Compress))
{
ds.WriteXml(gs);
}
不过,在 .NET 4.x 中创建文件并在 .NET Core 中读取它还行不通。甚至还有一个尚未修复的Github 问题。
由于安全性和兼容性问题,不鼓励使用BinaryFormatter 。此类可以根据文件的内容反序列化任何内容,包括意外或恶意类型。这也是导致此兼容性问题的原因 - 反序列化程序生成了一个System.String
与 .NET Core 运行时类型不匹配的新内容。
还有更普通的问题 - 添加或删除属性可能会导致兼容性问题,因为 BinaryFormatter 创建的类型与应用程序其余部分使用的类型不匹配。Version Tolerant Serialization中描述了该问题。
我不会屏住呼吸等待跨框架修复。该类型不受欢迎,积极劝阻且很少使用,这意味着很少有志愿者来修复它。与此同时,核心团队员工有更高优先级的问题,例如 gRPC 和稳定 WinForms 和 WPF 等流行堆栈。
推荐阅读
- javascript - 如何只允许输入整数
- logging - 如何在 Visual Studio Code 中设置调试控制台的日志级别以排除 console.debug 并包含 console.info?
- printing - 使用 GSView 5.0 打印后记
- anchor - 如何偏移与元素重叠的锚滚动?
- c# - 旋转单个图像列表图像
- google-search-console - 指定站点地图语言(所有站点地图的语言相同)
- scala - Executing Linux Command in Scala-Shell
- c# - 如何将图标声明为应用程序资源并用它们填充 GridView?
- matlab - ode45, 参数错误, 生长动力学
- javascript - GET http://equalityfits.com/bundle.js net::ERR_ABORTED 404(未找到)Apache2 WebServer