I have a C# solution with a referenced dll (also C# with the same .Net version). When I build the solution and run the resulting exe, without merging the exe and the refere
I had a situation where serialized data was being stored in SQL server by an old .NET service that had been in place for years. I needed to get the data out of SQL and ran into this also. I was able to refer to the .exe and make it work until I used the solution mentioned above. However my assembly names were different.
sealed class Version1ToVersion2DeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
// For each assemblyName/typeName that you want to deserialize to a different type, set typeToDeserialize to the desired type.
String assemVer1 = assemblyName;
String typeVer1 = typeName;
if (assemblyName == assemVer1 && typeName == typeVer1)
{
// To use a type from a different assembly version, change the version number.
assemblyName = Assembly.GetExecutingAssembly().FullName;
// To use a different type from the same assembly, change the type name.
typeName = "projectname.typename";
}
// The following line of code returns the type.
typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
return typeToDeserialize;
}
}
For anyone having this issue, trying to deserialize from a different assembly, I found this solution which seems to great for me using a small "BindChanger" class with a shared namespace for the Object type in question. https://www.daniweb.com/programming/software-development/threads/339638/deserializing-in-a-different-assembly
public sealed class DeserializationBinder : SerializationBinder
{
private readonly string _typeName;
private readonly Assembly _assembly;
public DeserializationBinder(Assembly assembly, string typeName)
{
_typeName = typeName;
_assembly = assembly;
}
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
if (!assemblyName.Contains("System") && !assemblyName.Contains("mscorlib"))
{
String currentAssembly = _assembly.FullName;
assemblyName = currentAssembly;
typeName = _typeName;
}
typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return typeToDeserialize;
}
}
SerializationBinder was also my solution. But I have the class in a DLL which is referenced. So i have to search in all load assemblies. I have modified the answers bevor with the parameter if the binder should search in dlls.
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ibKastl.Helper
{
public static class BinaryFormatterHelper
{
public static T Read<T>(string filename, Assembly currentAssembly)
{
T retunValue;
FileStream fileStream = new FileStream(filename, FileMode.Open);
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Binder = new SearchAssembliesBinder(currentAssembly,true);
retunValue = (T)binaryFormatter.Deserialize(fileStream);
}
finally
{
fileStream.Close();
}
return retunValue;
}
public static void Write<T>(T obj, string filename)
{
FileStream fileStream = new FileStream(filename, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fileStream, obj);
}
finally
{
fileStream.Close();
}
}
}
sealed class SearchAssembliesBinder : SerializationBinder
{
private readonly bool _searchInDlls;
private readonly Assembly _currentAssembly;
public SearchAssembliesBinder(Assembly currentAssembly, bool searchInDlls)
{
_currentAssembly = currentAssembly;
_searchInDlls = searchInDlls;
}
public override Type BindToType(string assemblyName, string typeName)
{
List<AssemblyName> assemblyNames = new List<AssemblyName>();
assemblyNames.Add(_currentAssembly.GetName()); // EXE
if (_searchInDlls)
{
assemblyNames.AddRange(_currentAssembly.GetReferencedAssemblies()); // DLLs
}
foreach (AssemblyName an in assemblyNames)
{
var typeToDeserialize = GetTypeToDeserialize(typeName, an);
if (typeToDeserialize != null)
{
return typeToDeserialize; // found
}
}
return null; // not found
}
private static Type GetTypeToDeserialize(string typeName, AssemblyName an)
{
string fullTypeName = string.Format("{0}, {1}", typeName, an.FullName);
var typeToDeserialize = Type.GetType(fullTypeName);
return typeToDeserialize;
}
}
}
Usage:
const string FILENAME = @"MyObject.dat";
// Serialize
BinaryFormatterHelper.Write(myObject1,FILENAME);
// Deserialize
MyObject myObject2 = BinaryFormatterHelper.Read<MyObject>(FILENAME, Assembly.GetExecutingAssembly()); // Current Assembly where the dll is referenced
You can do this by creating and adding a SerializationBinder sub class that will change the assembly name before the deserialization happens.
sealed class PreMergeToMergedDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
// For each assemblyName/typeName that you want to deserialize to
// a different type, set typeToDeserialize to the desired type.
String exeAssembly = Assembly.GetExecutingAssembly().FullName;
// The following line of code returns the type.
typeToDeserialize = Type.GetType(String.Format("{0}, {1}",
typeName, exeAssembly));
return typeToDeserialize;
}
}
Then when deserializating add this to the BinaryFormatter:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new PreMergeToMergedDeserializationBinder();
object obj = bf.Deserialize(ms);
i got the solution
sealed class VersionDeserializationBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type typeToDeserialize = null;
string currentAssemblyInfo = Assembly.GetExecutingAssembly().FullName;
//my modification
string currentAssemblyName = currentAssemblyInfo.Split(',')[0];
if (assemblyName.StartsWith(currentAssemblyName))assemblyName = currentAssemblyInfo;
typeToDeserialize = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
return typeToDeserialize;
}
}
Deserialization problem: Error when deserializing from a different program version