最近,我们将部分代码移到了不同的项目库中。
不幸的是,似乎这些数据已经用BinaryFormatter
序列化到数据库中(不要问我为什么,我不知道,我讨厌这个想法)。
现在我负责创建一个更新数据库的更新工具(当我们的软件根据版本检测到需要更新的数据库时,我们的软件会自动启动该工具):
我的问题是,当我尝试反序列化时,它会告诉我:
Unable to find assembly 'MyOldAssemblyName, Version=2.0.0.0, Culture=neutral, PublicKeyToken=a5b9cb7043cc16da'.
但是这个集会不再存在了。我把这个类放在我的“更新程序”项目中没有问题,但是我无法保持这个旧项目只包含这个文件。
有没有办法指定BinaryFormatter它必须反序列化它用指定类接收的Stream?
或者说程序集已重命名,或???
答案 0 :(得分:4)
要告诉它类型已在程序集之间移动(但它保留旧名称和名称空间),有时可以使用(在旧程序集中)[assembly:TypeForwardedTo(typeof(TheType))]
。这里的“有时”是因为你需要使用typeof
,这意味着你需要从旧程序集到新程序集的引用,这并不总是可行 - 但经常是(特别是如果您要将类型从UI层移动到POCO / DTO层,因为UI通常引用POCO / DTO)。
但是,如果您重命名了更改名称空间的类型,则需要您编写自定义“活页夹”(see here)。
应该注意的是BinaryFormatter
本质上是一个基于类型的序列化程序,在版本化或重构代码时,你总会遇到很多问题。如果类型不是“一次写入,那么永远不会改变它”,那么我 强烈 建议使用更灵活的东西 - 那就是合同基于而不是类型。基本上,除了BinaryFormatter
(或NetDataContractSerializer
)之外的任何事情:XmlSerializer
,DataContractSerializer
,protobuf-net,Json.NET等中的任何一个都会很好并且< strong>不关心你重新定位或重命名了一个类型。
答案 1 :(得分:2)
答案 2 :(得分:0)
我最近自己遇到了这个问题,并希望发布我是如何设法解决这个问题的。每个正常情况下序列化对象一切都是二进制格式化器反序列化时你可以使用一个Binder。使用下面的活页夹我简化了MSDN的解决方案,您需要做的就是将您使用的程序集的版本控制与类名一起交还。
public object DeserializeObject()
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Binder = new VersionDeserializer();
using (MemoryStream memoryStream = new MemoryStream())
{
try
{
memoryStream.Write(_data, _ptr, count);
memoryStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(memoryStream);
}
catch (Exception e)
{
return null;
}
}
}
sealed class VersionDeserializer: SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type deserializeType = null;
String thisAssembly = Assembly.GetExecutingAssembly().FullName;
deserializeType = Type.GetType(String.Format("{0}, {1}",
typeName, thisAssembly));
return deserializeType;
}
}