BinaryFormatter.Deserialize “unable to find assembly” after ILMerge

前端 未结 10 1076
囚心锁ツ
囚心锁ツ 2020-12-14 20:53

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

相关标签:
10条回答
  • 2020-12-14 21:17

    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;
            }
        }
    
    0 讨论(0)
  • 2020-12-14 21:18

    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

    0 讨论(0)
  • 2020-12-14 21:20
        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;
        }
    }
    
    0 讨论(0)
  • 2020-12-14 21:25

    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
    
    0 讨论(0)
  • 2020-12-14 21:27

    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);
    
    0 讨论(0)
  • 2020-12-14 21:29

    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

    0 讨论(0)
提交回复
热议问题