System.Runtime.Serialization.SerializationException: Unable to find assembly MyAssembly

后端 未结 9 1799
-上瘾入骨i
-上瘾入骨i 2020-12-19 04:00

So I\'ve found a bunch of threads on this topic but I don\'t think I\'ve found one that applies yet.

Basically my .exe loads a .dll (MyAssembly) file which does the

相关标签:
9条回答
  • 2020-12-19 04:16

    I just stumbled over the same issue and figured out that my fault was the existance of two versions of that assembly within my probing paths. That typically happens if you first did your assembly and afterwards fix a postbuild event to move it to where you really need it.

    0 讨论(0)
  • 2020-12-19 04:22

    Well, I used a trick that worked!

    sealed class CustomizedBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Type returntype = null;
            string sharedAssemblyName = "SharedAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
            assemblyName = Assembly.GetExecutingAssembly().FullName;
            typeName = typeName.Replace(sharedAssemblyName, assemblyName);
            returntype =
                    Type.GetType(String.Format("{0}, {1}",
                    typeName, assemblyName));
    
            return returntype;
        }
    
        public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
        {
            base.BindToName(serializedType, out assemblyName, out typeName);
            assemblyName = "SharedAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
        }
    }
    

    use the binder for binary formatters, like this:

    BinaryFormatter bf = new BinaryFormatter();
    bf.Binder = new CustomizedBinder();
    
    0 讨论(0)
  • 2020-12-19 04:22

    What I see in your code with both your serialize and deserialize is the use of the System.IO.Path class instead of the actual path to the file. I usually execute this as follows:

        static void Main(string[] args)
        {
            string filepath = @"C:\FileLocation\";
            string filename = "datasaved.bin";
            MyClass something = new MyClass();
    
            // serialize
            using ( FileStream strm = File.OpenWrite(Path.Combine(filepath, filename)))
            {
                BinaryFormatter ser = new BinaryFormatter();
                ser.Serialize(strm, something);
            }
    
            // deserialize
            using (FileStream strm = File.OpenRead(Path.Combine(filepath, filename)))
            {
                BinaryFormatter ser = new BinaryFormatter();
                something = ser.Deserialize(strm) as MyClass;
            }
        }
    

    Note two things: doing the Deserialize as will handle the object being null or not the expected type. Also I don't abuse the use of var.

    0 讨论(0)
  • 2020-12-19 04:25

    I had a specific case of the SerializationException described by the OP, and found a relatively simple solution. In my case, I am implementing a DeepClone extension method using the BinaryFormatter technique. My application also makes use of plug-ins, assemblies that I load programmatically. I encountered the SerializationException when the BinaryFormatter.Deserialize method was called for an object whose class is contained in a plug-in.

    I find this very strange, because, by definition, the containing assembly is loaded into my AppDomain. (I couldn't call an extension method on the object if it wasn't!) Apparently, the BinaryFormatter does not check the AppDomain to resolve assemblies.

    Many of the solutions suggested here for solving this problem seem to involve hard coding the name of the assembly, or class, into a custom SerializationBinder. This is not useful, as I want my DeepClone method to be as generic as possible. My answer to this problem (shown below) hooks the AssemblyResolve event in the current AppDomain and then searches the AppDomain (using LINQ) for the requested assembly. No hard coded assembly or class names required.

    Here is the code:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Runtime.Serialization;
    
    namespace StackOverflowDemo
    {
        public static class Extend
        {
            /// <summary>
            /// Static initializer is used to register the Resolve Event Handler
            /// </summary>
            static Extend()
            {
                AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler;
            }
    
            /// <summary>
            /// This resolver will find any Assembly that is already loaded into
            /// the current AppDomain and return it.
            /// <para/>
            /// You would think this would not be necessary, but the 
            /// BinaryFormatter.Deserialize method apparently can not 
            /// find an assembly that has been loaded programmatically
            /// as a plug-in, and whose DLL does not reside in the same
            /// folder as the executable file.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="args"></param>
            /// <returns></returns>
            private static Assembly ResolveEventHandler( object sender, ResolveEventArgs args )
            {
                var assemblies = AppDomain.CurrentDomain.GetAssemblies();
                Assembly result = (from a in assemblies where args.Name.Equals(a.FullName) select a).FirstOrDefault();
                return result;
            }
    
    
            /// <summary>
            /// Slow, and requires that the source be marked as [Serializable], but 
            /// clones *everything* and is not complicated.
            /// <para/>
            /// Note that by itself, this method will fail if an attempt is made to
            /// create a deep copy of an object whose class is contained in an assembly
            /// that was loaded programmatically (i.e., loaded as a plug-in).
            /// <para/>
            /// See https://stackoverflow.com/a/1213649
            /// <para/>
            /// and https://stackoverflow.com/a/23017515
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="src"></param>
            /// <returns></returns>
            public static T DeepClone<T>( this T src )
            {
                if (!typeof(T).IsSerializable)
                {
                    throw new ArgumentException(string.Format("[Extend.DeepClone] Type '{0}' is not Serializable", typeof(T).Name));
                }
    
                if (Object.ReferenceEquals(src, null))
                {
                    return default(T);
                }
    
                using (Stream stream = new MemoryStream())
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, src);
                    stream.Seek(0, SeekOrigin.Begin);
                    return (T)formatter.Deserialize(stream);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-19 04:26

    I'd like to build on Sean Ed-Man's answer, which is good, but doesn't work in my case.

    If you can instantiate the class but the BinaryFormatter can't resolve it, this may work for you.

    In my case, the calling assembly (PluginAssembly for this example) is being run as a plugin from the executable, in the form of a zip file. For some reason I can directly resolve the class (from NeededAssembly) when instantiating, but the BinaryFormatter can't resolve it. NeededAssembly is, of course, included as a reference to the PluginAssembly project, which is why I can instantiate. I don't know why the BinaryFormatter is different.

    Regardless, this is what worked for me:

    public class PluginAssembly
    {
        // (class code here)
    
        private sealed class CustomizedBinder : SerializationBinder
        {
            public override Type BindToType(string assemblyName, string typeName)
            {
                Type returntype = null;
                if (typeName.StartsWith("NeededAssembly.RemoteClient.MessagePayload"))
                {
                    returntype = typeof(MessagePayload);
                }
                else if (typeName.StartsWith("NeededAssembly.RemoteClient.ResultsPayload"))
                {
                    returntype = typeof(ResultsPayload);
                }
                else if (typeName.Equals("System.Collections.Generic.List`1[[NeededAssembly.ShortResult, NeededAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"))
                {
                    returntype = typeof(List<ShortResult>);
                }
                else
                {
                    returntype =
                            Type.GetType(String.Format("{0}, {1}",
                            typeName, assemblyName));
                }
                return returntype;
            }
    
            public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
            {
                base.BindToName(serializedType, out assemblyName, out typeName);
                if (serializedType.ToString().Contains("NeededAssembly"))
                {
                    assemblyName = typeof(MessagePayload).Assembly.FullName;
                }
            }
        }
    }
    

    Of course, don't forget to use it:

    BinaryFormatter bf = new BinaryFormatter();
    bf.Binder = new CustomizedBinder();
    

    Basically I simply get a typeof for the needed class, which works.

    0 讨论(0)
  • 2020-12-19 04:27

    There is yet another solution to this problem, which is to list the folder containing the assembly in App.config. You do this by adding a probing element, like this:

    <configuration>  
       <runtime>  
          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
             <probing privatePath="bin;bin2\subbin;bin3"/>  
          </assemblyBinding>  
       </runtime>  
    </configuration> 
    
    0 讨论(0)
提交回复
热议问题