If you have serialized an object using a previous version of a library or program, after you try to deserialize this object again you might encounter the following exception:
{“Exception has been thrown by the target of an invocation.”}
The inner exception might read:
[System.IO.FileLoadException] = {“Could not load file or assembly ‘Accord.Math, Version=2.13.1.0, Culture=neutral, PublicKeyToken=fa1a88e29555ccf7’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)”:”Accord.Math, Version=2.13.1.0, Culture=neutral, PublicKeyToken=fa1a88e29555ccf7″}
In this case, it is very likely that those exceptions are occurring because the .NET run-time is looking for an assembly with the specific version indicated above. Even if you have new assemblies with exact the same name and exact public key token, the .NET might still refuse to deserialize it.
In order to get around this, put the following static class into your application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public static class ExtensionMethods { private static readonly Object lockObj = new Object(); public static object DeserializeAnyVersion(this BinaryFormatter formatter, Stream stream) { lock (lockObj) { try { AppDomain.CurrentDomain.AssemblyResolve += resolve; return formatter.Deserialize(stream); } finally { AppDomain.CurrentDomain.AssemblyResolve -= resolve; } } } private static Assembly resolve(object sender, ResolveEventArgs args) { var display = new AssemblyName(args.Name); if (display.Name == args.Name) return null; return ((AppDomain)sender).Load(display.Name); } } |
Now, go back where you were using your deserializer and getting that exception, and instead of calling formatter.Deserialize
, call formatter.DeserializeAnyVersion
:
1 2 |
BinaryFormatter bf = new BinaryFormatter(); object o = bf.DeserializeAnyVersion(stream); |
Deserialization now might work as expected; but please keep in mind that we might be loosing some security here. However, this might be a concern only if your application is dynamically loading assemblies at run-time.
Here are some resources discussing the problem:
- Deserialize types moved across assemblies
- C# deserialization of System.Type throws for a type from a loaded assembly
- C# – BinaryFormatter.Deserialize is “Unable to find assembly”
Such extension method will also be included in the Accord.NET Framework.