AppDomain.CurrentDomain.AssemblyResolve asking for a .resources assembly?

后端 未结 2 1767
别那么骄傲
别那么骄傲 2020-11-30 04:38

using the code How to embed a satellite assembly into the EXE file provided by csharptest.net, I\'ve created a custom assembly resolver and embedded my assemblies in my reso

相关标签:
2条回答
  • 2020-11-30 05:20

    My situation was a bit more complex and the above solution did not work for me. (That is changing the AssemblyInfo.cs file)

    I have moved all my form and image resources to a seperate dll and the moment any of the images are used the 'filenotfoundexception' exception is thrown.

    The important information is the following:
    Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. See the following reference

    https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx

    The solution turned out to be very simple. If a resource file is requested in the form 'dllname.resources.dll' always return null;

    Here is the event code that I have adapted from other samples found. (I have commented the debugging lines - un-comment them if you have a problem using the code.

    Add this line in your class. It is used to prevent loading a dll more than once

        readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
    

    This is the event method.

    private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
            {
                Assembly assembly = null;
                string keyName = new AssemblyName(args.Name).Name;
                if (keyName.Contains(".resources"))
                {
                    return null;  // This line is what fixed the problem
                }
                if (_libs.ContainsKey(keyName))
                {
                    assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
                    return assembly;
                }
    
                string dllName = DllResourceName(keyName);
                //string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();   // Uncomment this line to debug the possible values for dllName
                using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
                {
                    if (stream == null)
                    {
                        Debug.Print("Error! Unable to find '" + dllName + "'");
                        // Uncomment the next lines to show message the moment an assembly is not found. (This will also stop for .Net assemblies
                        //MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
                        //Environment.Exit(0);
                        return null;
                    }
    
                    byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
                    assembly = Assembly.Load(buffer);
    
                    _libs[keyName] = assembly;
                    return assembly;
                }
            }
    
            private static string DllResourceName(string ddlName)
            {
                if (ddlName.Contains(".dll") == false) ddlName += ".dll";
    
                foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
                {
                    if (name.EndsWith(ddlName)) return name;
                }
                return ddlName;
            }
    
    0 讨论(0)
  • 2020-11-30 05:21

    Answering on my own;

    Adding this line to AssemblyInfo.cs solves it and resolver will not get asked for resources any-more.

    [assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
    

    Though this is a work-around should be carefully considered multi-language applications.

    More Info:

    • https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
    • http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
    • http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
    • http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx

    This approach fails for machines with non en-US cultures. A better approach is ignoring resources on assembly resolver;

    public Assembly Resolver(object sender, ResolveEventArgs args)
            {
                lock (this)
                {
                    Assembly assembly;
                    AssemblyName askedAssembly = new AssemblyName(args.Name);
    
                    string[] fields = args.Name.Split(',');
                    string name = fields[0];
                    string culture = fields[2];
                    // failing to ignore queries for satellite resource assemblies or using [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] 
                    // in AssemblyInfo.cs will crash the program on non en-US based system cultures.
                    if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
    
                    /* the actual assembly resolver */
                    ...
                }
          }
    
    0 讨论(0)
提交回复
热议问题