C# 调用Assembly.Load(byte())时激发AssemblyResolve事件
所以我有一个WPF项目,它正在引入DLL,这些DLL被我工作中的另一个项目使用。这是一堆依赖项,我一直在使用这种技术:将依赖项嵌入到单个可执行文件中 现在,当我在一个依赖项中调用特定方法时,我点击AssemblyResolve事件。我的OnResolveAssembly事件运行时,它将程序集作为嵌入式资源查找(酷!),并执行“返回assembly.Load(assembyRawBytes)”。如果我在这一点上点击F11(在OnResolveAssembly的开始处有一个断点),我将得到对同一事件的另一个调用。它也适用于相同的程序集(args.Name相同) 如果我让它运行,我会遇到堆栈溢出,因为我似乎永远无法逃避这个递归事件调用 MSDN文档并没有真正说明Assembly.Load何时会失败,除非出现FileNotFoundException或BadImageFormatException 在调用Assembly.Load之前,我已经尝试过将OnResolveAssembly解钩,但随后我的应用程序神秘地死亡,即使在VS下,它也会失败 我可能在这里违反了几条规则,但是对于从哪里开始寻找问题的一些想法是受欢迎的 我将开始在有问题的DLL中查找,看看是否有关于它的错误的提示(可能是一个混合程序集?) 以下是我的OnResolveAssembly处理程序:C# 调用Assembly.Load(byte())时激发AssemblyResolve事件,c#,.net,C#,.net,所以我有一个WPF项目,它正在引入DLL,这些DLL被我工作中的另一个项目使用。这是一堆依赖项,我一直在使用这种技术:将依赖项嵌入到单个可执行文件中 现在,当我在一个依赖项中调用特定方法时,我点击AssemblyResolve事件。我的OnResolveAssembly事件运行时,它将程序集作为嵌入式资源查找(酷!),并执行“返回assembly.Load(assembyRawBytes)”。如果我在这一点上点击F11(在OnResolveAssembly的开始处有一个断点),我将得到对同一事件
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
{
path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
}
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null)
return null;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
return assemblyDictionary[assemblyName.Name];
}
}
目前,我已通过迭代所有资源并尝试Assembly.Load并将其存储在字典中以供检索(在OnResolveAssembly事件期间)来解决此问题:
它现在似乎工作得很好(在我的第二个代码段中,“失败”的程序集将加载得很好),但我有兴趣了解为什么它在第一个代码段中不工作。从byte[]加载程序集是一个很好的方法,最终会进入.dll地狱(你会遇到太多/复杂的依赖项)。这里的问题是,尽管您将dll加载到AppDomain,但当您再次需要依赖类型的dll时,它不会自动解决。 我在这里评论了这个问题: 长话短说,程序集被加载到AppDomain内部的不同“上下文”中。Load(字节[])使用的上下文不会自动解析程序集 解决方案是跟踪加载的程序集,并返回已加载的程序集,而不是再次加载。在我对以下问题的回答中,这种方法有一个起点: 但我认为你的解决方法是正确的 顺便说一句,加载程序集两次是获得相同但不兼容类型的一种方法。是否曾将MyAssembly中的MyType对象强制转换为同一程序集中的MyType对象并得到null
这是一个热烈的“欢迎使用.dll地狱”。添加了我的代码和我发现的一个解决方法。@JonathanYee你真的从调用
Assembly.Load(byte[])中得到AssemblyResolve
了吗?这正是我正在寻找的情况,但我无法构建这样一个示例。你能提供更多的细节吗?
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] resources = executingAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(".dll"))
{
using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
}
}
}
}
App.Main();
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary[path];
}
return null;
}