我有这段代码:
public byte[] SerializeToBlob()
{
using (var buffer = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(buffer, this);
buffer.Position = 0;
return buffer.ToArray();
}
}
public static ActionData DeserializeFromBlob(byte[] state)
{
using (var buffer = new MemoryStream(state))
{
var formatter = new BinaryFormatter();
var result = formatter.Deserialize(buffer);
return (ActionData) result;
}
}
我称之为:
byte[] actionDataBlob = ad.SerializeToBlob();
var ad1 = ActionData.DeserializeFromBlob(actionDataBlob);
但是,当我尝试将反序列化对象强制转换为其类型时,我得到一个InvalidCastException:
[A] ActionData无法转换为 [B] ActionData。 A型起源于 'XXXX.XXXX.Auditing,版本= 1.0.76.0, Culture = neutral,PublicKeyToken = null' 在位置的“默认”上下文中 “C:\用户\克雷格\应用程序数据\本地的\ Temp \临时 ASP.NET 文件\根\ 5d978e5b \ ffc57fe1 \组件\ DL3 \ 2b1e5f8f \ 102c846e_9506ca01 \ XXXX.XXXX.Auditing.DLL”。 B型起源于 'XXXX.XXXX.Auditing,版本= 1.0.76.0, Culture = neutral,PublicKeyToken = null' 在上下文'LoadNeither'中 位置'F:\ Visual Studio 项目\ XXXXXXXXX \源\ XXXX.XXXX.SilverlightClient.Web \ BIN \ XXXX.XXXX.Auditing.dll”。
(XXXX.XXXX会掩盖客户的名字)
是什么给出了?
我现在在这里问了一个相关的问题:
How should I serialize some simple auditing data for storing in a SQL table?
答案 0 :(得分:4)
听起来我在不同的程序集(或Web应用程序)中拥有相同的类。 BinaryFormatter包含序列化中的类型元数据,这意味着只有完全相同的程序集才能执行。 2解决方案:
就个人而言,我会选择第二种,原因不仅限于此。可能的选择:
哪个最好取决于场景。
答案 1 :(得分:4)
您已在不同的loader contexts中加载了两次相同的程序集。例如。你碰巧首先加载了XXX.Auditing Assembly.LoadFrom()
,然后其他一些(或你的)程序集正常加载它。事实上,二进制反序列化器可能是第二次加载程序集的人,虽然我不知道为什么(没有使用ASP.NET的经验)。
答案 2 :(得分:2)
确定。我刚遇到同样的问题。
在我的情况下,问题是因为我从一个字节数组加载一个程序集(我正在使用一个插件模型,所以这是相当普遍的用途)并且反序列化一个对象但它不会使用相同的方法进行转换消息作为原始问题。
起初我认为这只是因为序列化程序和dll版本控制......所以我编写了自己的序列化程序并再次遇到了同样的问题。
这个问题确实来自于类型创建。在我的反序列化例程中,我使用熟悉的Type.GetType(string)方法并传递AssemblyQualifiedName,它确实有效,并且对于所有位于mscorlib之外的类型,它都是必需的。 好吧,事实证明GetType没有遍历加载的程序集列表来尝试找到匹配但是将它留给融合解析器。
这意味着找不到在“Load”之外的任何上下文中加载的程序集中的任何类型(在异常消息中也称为“Default”),并且GetType会尝试正常加载程序集。
在我的例子中,这种行为导致组件的2个实例被加载到appdomain中:从我的字节数组开始,另一个从fusion找到的磁盘。
我通过枚举appdomain中加载的程序集来寻找匹配的程序集名称(从我的AssemblyQualifiedName解析)来解决这个问题。一旦找到,我使用该特定程序集(Assembly.GetType(String))创建了我的类型(减去程序集信息)。
这是允许我克服这个问题的代码:
Dim ot As System.Type
Dim tname = "MyType"
Dim aname = "MyPlugin"
'// The following lambda expression returns only assemblies that match my assembly name
'// Your assembly name could be a fully qualified name or just the simple assembly name
'// I chose to use the simple name so that i didn't have to store unnecessary data and because i didn't want version specific info
Dim asms = AppDomain.CurrentDomain.GetAssemblies().Where(Function(__) __.GetName.Name.Equals(aname))
'If there is only one assembly loaded...use it
If asms.Count = 1 Then
ot = asms(0).GetType(tname)
'// If there are multiple assemblies loaded (with the same name), i'm picking the one that is loaded from disk, if such is available, otherwise default back to the first one that was loaded into the appdomain
'// If you do have multiple assemblies loaded, it's because you (or .NET) has loaded them in different contexts. You might need to adjust for which context you want. I suppose you could pass the desired context in as a parameter and look for it
ElseIf asms.Count > 1 Then
Dim asm = asms.FirstOrDefault(Function(__) Not String.IsNullOrEmpty(__.Location))
If asm IsNot Nothing Then
ot = asm.GetType(tname)
Else
ot = asms(0).GetType(tname)
End If
Else
'// not yet loaded...use default type resolution from Type.GetType
ot = Type.GetType(tname & "," & aname)
End If
Dim obj
'// Note that the method here is using the already resolved System.Type from above.
'// This is important because it causes Activator to create an instance from the assembly
'// that we really want and not one from fusion's resolver.
obj = Activator.CreateInstance(ot)
希望这对其他人有帮助。
-Eriq
答案 3 :(得分:1)
最后,我认为我的问题在于动态加载。当我使用XmlSerializer实现它时,我遇到了完全相同的问题。
解决方案是将我想要序列化的类放在一个单独的程序集中,这样它们就不会动态加载。
答案 4 :(得分:0)
我有同样的问题和完全相同的错误,但不是一切,但偶尔。即时通讯使用linqtoSQL,数据列表已序列化,然后通过
访问filteredTasks = (List<App.Task.Entity.GetAllTasksResult>)Session["myTaskList"];
答案 5 :(得分:0)
我在使用.net代码的Microsoft Office InfoPath表单中遇到同样的问题。甚至微软自己的代码也在这个问题上绊倒了。
是的我可以看到它同时从两个不同的位置加载.. \应用程序数据\本地\组件\ DL3 ...
以及
\应用程序数据\本地\的Micorosoft \的InfoPath \ FormCache4 ...
叹息