跨不同框架版本的.NET序列化的稳定性

w41d8nur  于 2023-03-24  发布在  .NET
关注(0)|答案(7)|浏览(170)

我正在处理的一个项目需要在关闭之前序列化数据结构,并在再次启动时从该序列化数据恢复其状态。
去年,我们正在为.NET 1.1构建,并遇到了一个棘手的问题

  • 我们的代码在.NET 2.0上运行
  • 一位客户升级了一些软件,但不知何故将1.1设置为默认值
  • 我们的代码在.NET 1.1上运行,无法反序列化其存储的状态

这个特殊的问题已经通过禁止特定的软件升级而“解决”了,现在我们的目标是.NET 2.0框架(所以我们不可能在1.1上运行)。
如果我们使用<supportedVersion>将代码修改为2.0.50727,那么在2.0.50727.1434和2.0.50727.nnnn之间发生更改的可能性有多大(将来的某个版本)-正在序列化的数据结构是标准类库中的数组、Map、字符串等。
另外,是否保证即使在进一步的.NET升级后,也会始终安装2.0.50727框架?欢迎指向Microsoft文档的指针。

os8fio9y

os8fio9y1#

框架版本之间发生变化的可能性很低(但不是零!)。其目的是您应该能够使用二进制序列化和远程处理在运行不同框架版本的客户端和服务器之间进行通信。.NET 1.x和2.0 is a bug之间的不兼容性有可用的补丁。
然而,二进制序列化还有其他问题,特别是对序列化结构的版本控制支持不足。从您描述的用例来看,XML序列化是显而易见的选择:DataContractSerializer比XmlSerializer更灵活,如果你不介意依赖于.NET 3.x的话。
你不能保证.NET framework 2.0将始终安装在Windows的未来版本上。但我相信微软将努力确保大多数.NET 2.0应用程序将在.NET 4.x和更高版本上运行。我没有任何参考资料:任何这样的承诺在任何情况下都只会真正适用于下一个版本的Windows(Windows 7)。

4jb9z9bj

4jb9z9bj2#

经验法则通常是:XML序列化应该能够在新的框架版本中生存下来,因此可以长期存储,但二进制序列化不能(因此只能是暂时的)。

ccgok5k5

ccgok5k53#

你使用的是什么序列化器?在很多方面,像XmlSerializer或DataContractSerializer这样的序列化器可以让你避免很多细节,并提供更简单的可扩展性选项。在某些时候,一个新的CLR版本无疑是必要的-所以我不认为任何人可以对2.0.50727做出任何保证;不过,短期内你应该是安全的。我希望能有更少的突破性变化……
[在另一份答复的说明后更新]
如果你需要一个二进制格式的空间/性能的原因,那么另一个选择是使用不同的二进制序列化器。例如,protobuf-net工作在所有.NET变种 *,但二进制格式(由谷歌提供)是跨平台兼容(Java,C++等)-使其非常便携,快速,小巧。

  • =我还没有在微框架上尝试过,但是CF、Silverlight、Mono、.NET 2.0等都支持。
e4eetjau

e4eetjau4#

如果兼容性是一个问题,ISerializable接口可能是你正在寻找的解决方案。这个接口让你可以更好地控制项目的序列化方式。有关更多信息,请尝试article on msdn

xdnvmnnf

xdnvmnnf5#

我有两件事要补充其他的答案...
首先,使用定制的SerializationBinder可以避免导入遗留序列化数据时遇到的许多困难。
其次,我认为必须为任何持久化数据编写大量的单元测试。我总是特别做两个测试:
1.往返测试-你能序列化和反序列化你的对象,并得到完全相同的东西回来吗?
1.旧版导入测试-确保您从应用的每个发布版本中导出了序列化数据的版本。导入数据并检查所有内容是否按预期返回。

332nm8kg

332nm8kg6#

您不必为了获得更高的灵活性和版本控制而使用XML。
我使用了Simon休伊特的开源库,参见 * Optimizing Serialization in .NET - part 2 * 而不是默认的.NET序列化。它提供了一些自动化,但本质上你可以控制序列化和反序列化的信息流。对于版本控制,(文件)版本可以首先序列化,在反序列化时,信息流的解释方式取决于版本。
这很容易做到,尽管由于显式的序列化/反序列化而有些繁琐。
作为奖励,它的速度提高了20-40倍,并且对于大型数据集占用的空间更少(但在您的情况下可能不重要)。

7rfyedvj

7rfyedvj7#

从理论上讲,XML应该总是可以在不同版本的.NET Framework/.NET Core/. NET之间移植的,但总有例外。
例如,如果您正在以XML格式移动System.Data.DataTable s,并且其中一些数据表包含System.Guid类型的列,那么您可能会感到惊讶!请考虑以下示例代码:

using System;
using System.Data;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

public class Program
{
    internal static string SerializeToXml<T>(T input)
    {
        var writerSettings = new XmlWriterSettings()
        {
            Encoding = new UTF8Encoding(false),
            Indent = true
        };
        using (var stream = new MemoryStream())
        using (var writer = XmlWriter.Create(stream, writerSettings))
        {
            (new XmlSerializer(typeof(T))).Serialize(writer, input);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }

    public static void Main()
    {
        var dt = new DataTable("Name");
        dt.Columns.Add("Example", typeof(Guid));
        Console.WriteLine(SerializeToXml(dt));
    }
}

与大多数其他系统类型不同,System.Guid在列定义中包含一个特定于版本的msdata:DataType属性,当不兼容的运行时尝试反序列化System.ArgumentException: Column requires a valid DataType时,该属性将抛出一个 Package System.ArgumentException: Column requires a valid DataTypeSystem.InvalidOperationException: There is an error in XML document (.., ...)

.NET Framework 4.7.2输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <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:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" 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" />
</DataTable>

.NET Core 3.1输出:(是的,输出www.example.com版本4.0.0.0)

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <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:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" 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" />
</DataTable>

.NET 5输出:

.NET 5
<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <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:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" 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" />
</DataTable>

.NET 6输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <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:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" 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" />
</DataTable>

.NET 7输出:

<?xml version="1.0" encoding="utf-8"?>
<DataTable>
  <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:MainDataTable="Name" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="Name">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Example" msdata:DataType="System.Guid, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" type="xs:string" 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" />
</DataTable>

相关问题