I'm getting an:
System.Runtime.Serialization.SerializationException: Unable to find assembly 'myNameSpace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
When trying to deserialize some data in another program than the program I serialized it with.
After some googling I've found out that apparently this can only be done using a shared assembly.
However, my database is full with this serialized objects, and I need a utility program to get them out. Is there a way to override this behavior and just feed it the exact same class and force it do deserialize?
I already found this snippet, but I don't understand how and where I should put/use this.
static constructor() {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
Assembly ayResult = null;
string sShortAssemblyName = args.Name.Split(',')[0];
Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly ayAssembly in ayAssemblies) {
if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) {
ayResult = ayAssembly;
break;
}
}
return ayResult;
}
Serialization is the process of storing the state of an object to a storage medium. In binary serialization, the public and private fields of the object and the name of the class, including the assembly containing the class, are converted to a stream of bytes, which is then written to a data stream.
The class BinaryFormatter in C# performs the actions of “serialization” and “deserialization” of binary data. It takes simple data structures such as integers (int), decimal numbers (float), and collections of letters and numbers (string) and can convert them into a binary format.
BinaryFormatter is used for serialization. It helps you to map a C# object to a binary representation which you can write to a file, a network stream etc.
Formatter is the abstract base class for all runtime serialization formatters, and provides some helper methods for implementing the IFormatter interface.
JTtheGeek's answer is correct that a custom SerializationBinder
is the way to handle this problem. The example code given in that answer isn't sufficient for my use case, though. I needed something that could:
This is what I came up with:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Company.Product.Common.Serialize
{
/// <summary>
/// A Serialization Binder that allows inexact matches (version number or namespace).
/// </summary>
public sealed class AllowInexactMatchSerializationBinder : System.Runtime.Serialization.SerializationBinder
{
static private Dictionary<string, Type> typeBindings = new Dictionary<string, Type>();
/// <summary>
/// When overridden in a derived class, controls the binding of a serialized object to a type.
/// </summary>
/// <param name="assemblyName">Specifies the <see cref="T:System.Reflection.Assembly" /> name of the serialized object.</param>
/// <param name="typeName">Specifies the <see cref="T:System.Type" /> name of the serialized object.</param>
/// <returns>
/// The type of the object the formatter creates a new instance of.
/// </returns>
public override Type BindToType(string assemblyName, string typeName)
{
Type type;
var assemblyQualifiedTypeName = String.Format("{0}, {1}", typeName, assemblyName);
// use cached result if it exists
if (typeBindings.TryGetValue(assemblyQualifiedTypeName, out type))
{
return type;
}
// try the fully qualified name
try { type = Type.GetType(assemblyQualifiedTypeName); }
catch { type = null; }
if (type == null)
{
// allow any assembly version
var assemblyNameWithoutVersion = assemblyName.Remove(assemblyName.IndexOf(','));
var assemblyQualifiedTypeNameWithoutVersion = String.Format("{0}, {1}", typeName, assemblyNameWithoutVersion);
try { type = Type.GetType(assemblyQualifiedTypeNameWithoutVersion); }
catch { type = null; }
}
if (type == null)
{
// check all assemblies for type full name
try
{
type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.ExportedTypes)
.Where(a => a.FullName == typeName)
.FirstOrDefault();
}
catch { type = null; }
}
if (type == null)
{
// check all assemblies for type name
var name = typeName.Split('.').Last();
try
{
type = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.ExportedTypes)
.Where(a => a.Name == name)
.FirstOrDefault();
}
catch { type = null; }
}
typeBindings[assemblyQualifiedTypeName] = type;
return type;
}
}
}
You can get around this issue without needing the DLL if you know the object...
http://spazzarama.com/2009/06/25/binary-deserialize-unable-to-find-assembly/
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder(VS.71).aspx
Use the “System.Runtime.Serialization.SerializationBinder” class. By inheriting from this class it is possible to redirect all the requests for types from the binary formatter to the types of your choice.
Here is a sample that will allow the types to be found in the current assembly regardless of which version of the assembly originally created the serialized stream:
sealed class AllowAllAssemblyVersionsDeserializationBinder : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
String currentAssembly = Assembly.GetExecutingAssembly().FullName;
// In this case we are always using the current assembly
assemblyName = currentAssembly;
// Get the type using the typeName and assemblyName
Type typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return typeToDeserialize;
}
}
public static MyRequestObject Deserialize(byte[] b)
{
MyRequestObject mro = null;
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var ms = new System.IO.MemoryStream(b))
{
// To prevent errors serializing between version number differences (e.g. Version 1 serializes, and Version 2 deserializes)
formatter.Binder = new AllowAllAssemblyVersionsDeserializationBinder();
// Allow the exceptions to bubble up
// System.ArgumentNullException
// System.Runtime.Serialization.SerializationException
// System.Security.SecurityException
mro = (MyRequestObject)formatter.Deserialize(ms);
ms.Close();
return mro;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With