在ILMerge之后,BinaryFormatter.Deserialize“无法找到程序集”

我有一个带有引用的dll的C#解决方案(也是具有相同.Net版本的C#)。 当我构建解决方案并运行生成的exe时,没有合并exe和引用的dll,一切正常。

现在我想将这些合并到一个exe中。 我运行ILMerge,一切似乎都正常。 我尝试执行exe,它似乎运行正常,直到它尝试反序列化引用的DLL中定义的对象。

using (Stream fstream = new FileStream(file_path, FileMode.Open)) { BinaryFormatter bf = new BinaryFormatter(); return bf.Deserialize(fstream) as ControlledRuleCollection; // throws unable to find assembly exception } 

可能有一些ILMerge选项我在这里丢失了吗?

听起来你已经在DLL中序列化了一个对象,然后将所有程序集与ILMerge合并,现在正在尝试反序列化该对象。 这根本行不通。 二进制序列化的反序列化过程将尝试从原始DLL加载对象的类型。 ILMerge后不存在此DLL,因此反序列化将失败。

序列化和反序列化过程需要在合并前或合并后进行操作。 它不能混合

您可以通过创建和添加SerializationBinder子类来执行此操作,该子类将在反序列化发生之前更改程序集名称。

 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; } } 

然后在反序列化时将其添加到BinaryFormatter:

 BinaryFormatter bf = new BinaryFormatter(); bf.Binder = new PreMergeToMergedDeserializationBinder(); object obj = bf.Deserialize(ms); 

您可能已经从单独的程序集序列化了该程序集,然后尝试使用另一个程序集(或同一程序集的较新版本)对其进行反序列化。

这里有一些讨论

SerializationBinder也是我的解决方案。 但我在引用的DLL中有类。 所以我必须搜索所有负载组件。 如果活页夹应在dll中搜索,我已使用参数修改了答案bevor。

 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(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 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 assemblyNames = new List(); 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; } } } 

用法:

 const string FILENAME = @"MyObject.dat"; // Serialize BinaryFormatterHelper.Write(myObject1,FILENAME); // Deserialize MyObject myObject2 = BinaryFormatterHelper.Read(FILENAME, Assembly.GetExecutingAssembly()); // Current Assembly where the dll is referenced 

如果您将程序集合并到现有程序集(例如,所有DLL到EXE),您可以使用此答案中提出的解决方案:

 // AssemblyInfo.cs for My.exe [assembly: TypeForwardedTo(typeof(SomeTypeFromMergedDLL))] 

这至少适用于反合并解组。 IL-Merge也仍然通过; 即使您无法使用类型转发编译到同一程序集的类型…

我还没有尝试,如果序列化工作合并后。 但我会更新我的答案。

我有一种情况,序列化数据存储在SQL服务器中的旧.NET服务已存在多年。 我需要从SQL中获取数据并遇到这种情况。 我能够引用.exe并使其工作,直到我使用上面提到的解决方案。 但是我的集会名称不同。

 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; } } 

我得到了解决方案

  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; } 

}

反序列化问题:从其他程序版本反序列化时出错

  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; } } 

对于任何有这个问题的人,尝试从不同的程序集反序列化,我发现这个解决方案似乎很适合我使用一个小的“BindChanger”类,该类具有相关Object类型的共享命名空间。 https://www.daniweb.com/programming/software-development/threads/339638/deserializing-in-a-different-assembly