【问题标题】:AppDomain.CurrentDomain.AssemblyResolve asking for a <AppName>.resources assembly?AppDomain.CurrentDomain.AssemblyResolve 要求 <AppName>.resources 程序集?
【发布时间】:2011-05-21 01:43:53
【问题描述】:

使用 csharptest.net 提供的代码How to embed a satellite assembly into the EXE file,我创建了一个自定义程序集解析器并将我的程序集嵌入到我的资源中。

我可以成功解析我使用的程序集,但不知何故 AppDomain.CurrentDomain.AssemblyResolve 要求一个名为“AppName.resources”的程序集,特别是“MyProgram.resources,Version=0.15.3992.31638,Culture=en-US,PublicKeyToken=null”不知道怎么解决?

我尝试禁用从资源加载我的自定义程序集(将我所有的程序集 dll 放在程序目录中)并且刚刚启用 AppDomain.CurrentDomain.AssemblyResolve,但它仍然要求它。

我对此有点困惑,如果您能帮助我,将不胜感激。

这是我的代码给感兴趣的人;

static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
    Assembly assembly = null;
    string name = args.Name.Substring(0, args.Name.IndexOf(','));
    if (name == "MyProgram.resources") return null;
    else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);

    lock (_loadedAssemblies)
    {
        if (!_loadedAssemblies.TryGetValue(name, out assembly))
        {
            using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
            {
                if (io == null)
                {
                    MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(-1);
                }
                using (BinaryReader binaryReader = new BinaryReader(io))
                {
                    assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
                    _loadedAssemblies.Add(name, assembly);
                }
            }
        }
    }

    return assembly;
}

【问题讨论】:

    标签: c# assemblies assembly-resolution


    【解决方案1】:

    我自己回答;

    将此行添加到 AssemblyInfo.cs 即可解决此问题,并且解析器将不再被要求提供资源。

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

    虽然这是一种变通方法,但应仔细考虑多语言应用程序。

    更多信息:

    这种方法不适用于具有非美国文化的机器。更好的方法是忽略程序集解析器上的资源;

    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 */
                    ...
                }
          }
    

    【讨论】:

    • 我在某处读到返回 null 在这种情况下无济于事;你能确认一下吗?
    • “更好的方法对我有用”。让我有点头疼。谷歌直接得到一个答案。我喜欢它。
    • 我不明白“中性”检查背后的逻辑。如果文化是“中性的”,它将尝试正常加载程序集,但由于没有该名称的程序集,这不会仍然失败吗?
    【解决方案2】:

    我的情况有点复杂,上述解决方案对我不起作用。 (即更改 AssemblyInfo.cs 文件)

    我已将所有表单和图像资源移动到一个单独的 dll 中,并且在使用任何图像时会引发“filenotfoundexception”异常。

    重要信息如下:
    从 .NET Framework 4 开始,为所有程序集(包括资源程序集)引发 ResolveEventHandler 事件。请参阅以下参考

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

    结果证明解决方案非常简单。如果以 'dllname.resources.dll' 形式请求资源文件,则始终返回 null;

    这是我从找到的其他示例中改编而来的事件代码。 (我已经注释了调试行 - 如果您在使用代码时遇到问题,请取消注释。

    在您的课程中添加这一行。它用于防止多次加载 dll

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

    这是事件方法。

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

    【讨论】:

    • 我建议将测试 if (keyName.Contains(".resources")) 更改为 if (keyName.EndsWith(".resources")),因为例如,如果您有一个名为“myApp.resourcesystem”的程序集,这会给您带来意想不到的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-30
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    相关资源
    最近更新 更多