Assembly.Load 及其怪异之处..."找不到文件或程序集"错误



我们的本地化团队试图使用LocBaml(.NET Framework版本,4.6.1(来本地化一些资源。他们不断收到错误,说"找不到文件或程序集..."所以,我查看了它,看到 x.resources.dll 文件必须与 x.dll 位于同一目录中的注释。("x"只是表示某个名称(。试过了,仍然出现同样的错误。 然后,我构建了一个调试版本,并下载了 .NET 源代码。事实证明,.NET 的内部发生了一些异常。如果我能总结一下,它在尝试执行Assembly.Load("x"(时失败了。 所以我写了一个程序试图复制这种情况......

using System;
using System.Reflection;
using System.Linq;
namespace Nothing
{
class Loader
{
public static void Main(string[] args)
{
try
{
if (args.Count() == 1)
{
Assembly asm = Assembly.Load(args[0]);
Console.WriteLine($"Name of asembly: {asm.FullName}");
}
else
{
Console.WriteLine("Need to specify filename");
}
}
catch (Exception x)
{
Console.WriteLine("Exception: {0}", x);
}
}
}
}

该文件被命名为 AsmLoader.cs并编译为 AsmLoader.exe。

从目录中 x.dll 输入,我输入了 \path\to\AsmLoader.exe x.dll 和 \path\to\AsmLoader.exe x。 相同的错误,"找不到文件或程序集...">

查看异常的堆栈跟踪,发现"代码库"是堆栈上某些函数的参数。考虑了一下,并将 AsmLoader.exe 复制到与 x.dll 相同的目录中。

给了.\AsmLoader.exe x.dll一个尝试。还是同样的错误。请记住,例外的参数只是"x"。已尝试 .\AsmLoader.exe x .... 宾果游戏。。。工作。为了咧嘴笑,将 LocBaml.exe 和它的 .config 文件复制到同一个目录,并尝试 .\LocBaml x.resources.dll ...叮,叮,叮...成功。最后。

所以,现在,我只告诉本地化团队将 LocBaml 复制到与文件相同的目录中,一切都应该很好。

但是,我不禁觉得这可以通过代码以某种方式解决。如何更改示例中的代码,以便 AsmLoader.exe 不必与我要加载的 DLL 位于同一目录中?我甚至更改了我的路径环境变量以确保 AsmLoader.exe并且两个 x.dll 目录都在路径中。那没用...

那么我需要更改什么才能让它在我的基本程序中工作......然后也许我可以为LocBaml做同样的事情......???

好吧,我想出了一个解决方案,将AssemblyResolve事件处理程序添加到当前的应用程序域。为这个简单的例子和我重建的 LocBaml 解决了它......

在主要中添加:

AppDomain.CurrentDomain.AssemblyResolve += LoadFromCurrentDirectory;

实现 LoadFromCurrentDirect,如下所示:

static Assembly LoadFromCurrentDirectory(object sender, ResolveEventArgs args)
{
string name = args.Name;
bool bCheckVersion = false;
int idx = name.IndexOf(',');
if (idx != -1)
{
name = name.Substring(0, idx);
bCheckVersion = true;
}
string sCurrentDir = Directory.GetCurrentDirectory();
if (!name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) && !name.EndsWith(".exe"))
{
string[] exts = { ".dll", ".exe" };
foreach( string ext in exts)
{
string tryPath = Path.Combine(sCurrentDir, name + ext);
if (File.Exists(tryPath))
{
name = name += ext;
break;
}
}
}
string path = Path.Combine(sCurrentDir, name);
if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
Assembly assembly = Assembly.LoadFrom(path);
if (assembly != null & bCheckVersion)
{
if (assembly.FullName != args.Name)
return null;
}
return assembly;
}
else
{
var reqAsm = args.RequestingAssembly;
if (reqAsm != null)
{
string requestingName = reqAsm.GetName().FullName;
Console.WriteLine($"Could not resolve {name}, {path}, requested by {requestingName}");
}
else
{
Console.WriteLine($"Could not resolve {args.Name}, {path}");
}
}
return null;
}

我相信可以对其进行优化以添加全局目录列表,或者在搜索要加载的文件时使用路径。但是,对于我们的用例,工作正常。当我将其添加到我们的 LocBaml 代码中时,它为我们解决了加载问题......也摆脱了将 en\x.resources.dll 文件复制到我们的输出目录的必要性。只要我们从输出目录运行程序,LocBaml 就会完成解析。

最新更新