GetExportedTypes() FileNotFoundException:找不到程序集

发布于 2024-12-03 22:48:52 字数 2099 浏览 0 评论 0原文

我的任务:在 dll 或 exe 文件中查找所有表单(WindowsForm 或 WPF,无关紧要)并返回该列表。理论上是可行的(意思是:如果我有一个带有 WPF 或 WindowsForm 的程序集,我的代码可以设法获取所有表单、文本框、标签等)。当涉及“真正的”组件时,它会失败。为每个“自定义”程序集调用 GetExportedTypes() 时,我都会遇到 FileNotFound 异常(找到 .NET 程序集,没有问题)。我已经使用 GetReferencedAssemblies() 来加载引用的程序集 (Reflection.Assembly.LoadFrom),是的,它确实有效(所有程序集都找到并加载到 AppDomain 中),但它没有帮助。

我检查了版本号(它们匹配),我将可执行文件和程序集复制到包含所有引用程序集的一个目录中,但不起作用。

这是我的代码,也许有人知道我(显然)做错了什么:

foreach (AssemblyName reference in selectedAssembly.GetReferencedAssemblies())
{
      if (System.IO.File.Exists(
             System.IO.Path.GetDirectoryName(selectedAssembly.Location) + 
                @"\" + reference.Name + ".dll"))
      {
         System.Reflection.Assembly.LoadFrom(
            System.IO.Path.GetDirectoryName(selectedAssembly.Location) + 
               @"\" + reference.Name + ".dll");
      }
      else if (System.IO.File.Exists(@"C:\dll\" + reference.Name + ".dll"))
      {
         System.Reflection.Assembly.LoadFrom(@"C:\dll\" + reference.Name + ".dll");
      }
      else
      {
         System.Reflection.Assembly.ReflectionOnlyLoad(reference.FullName);
      }

      selectedAssembly.GetExportedTypes();       
}

首先检查引用的 dll 是否存在于程序集所在的目录中,如果不存在,则检查它是否存在于 C:\dll 中,如果不存在尝试使用 GAC。它确实有效,并且我没有任何错误,但是当我到达 GetExportedTypes 时,它会失败,并在第一个自定义库上出现 FileNotFound 异常。

*编辑1“真正的程序集”是什么意思:我的意思是更复杂并且引用非标准.NET库/程序集的程序集


感谢fuslogvw.exe Hans Passant的提示,但是“”是什么意思用这样的代码”?


好吧,我使用了 fuslogvw.exe,并且对于“selectedAssembly”引用的每个 dll,我都遇到了两个异常。 第一个说的是类似的话 “绑定从 LoadFrom-context 开始 系统拥有的映像未在 LoadFrom-Context 中搜索”,

另一个 logentry 表示无法找到 selectedAssembly 引用的 dll,它尝试从应用程序的基本路径和下面的所有目录下载它...但不是从它的实际位置...所以,关键问题:如何将 Load-context 更改为 LoadFrom?为什么 .NET 对此如此顽固?我的意思是程序集是在 AppDomain 中加载的,它不应该关心组装的实际位置


问题已解决。 http://ayende.com/blog/1376/solving-the - assembly-load-context-problem

我将其实现到我现有的类中(删除了 static 关键字并将 Init 方法的主体放入我的方法中),编译它并且它起作用了。

谢谢你们的帮助。

My task: Find all Forms (WindowsForm or WPF, doesn't matter) in a dll or exe file and return that list. In theory that works (meaning: if I've an assembly with a WPF or WindowsForm my code manages to get all Forms, TextBoxes, Labels etc. ). When it comes to "real" assemblies it fails. I get FileNotFound exceptions when calling GetExportedTypes() for every "custom" assembly (.NET assemblies are found, no problems there). I already use GetReferencedAssemblies() to load the referenced assemblies (Reflection.Assembly.LoadFrom) and yes it does work (all assemblies are found and loaded into the AppDomain) but it doesn't help.

I checked the version numbers (they match), I copied my executable and the assembly into one directory with all referenced assemblies, doesn't work.

Here is my code, maybe someone figures out what I'm (obviously) doing wrong:

foreach (AssemblyName reference in selectedAssembly.GetReferencedAssemblies())
{
      if (System.IO.File.Exists(
             System.IO.Path.GetDirectoryName(selectedAssembly.Location) + 
                @"\" + reference.Name + ".dll"))
      {
         System.Reflection.Assembly.LoadFrom(
            System.IO.Path.GetDirectoryName(selectedAssembly.Location) + 
               @"\" + reference.Name + ".dll");
      }
      else if (System.IO.File.Exists(@"C:\dll\" + reference.Name + ".dll"))
      {
         System.Reflection.Assembly.LoadFrom(@"C:\dll\" + reference.Name + ".dll");
      }
      else
      {
         System.Reflection.Assembly.ReflectionOnlyLoad(reference.FullName);
      }

      selectedAssembly.GetExportedTypes();       
}

at first check if the referenced dll exists in the directory where the assembly is, if not check if it exists in C:\dll and if it's not there try and use the GAC. it does work and I've no errors from there but as soon as I come to GetExportedTypes it fails with a FileNotFound exception on the first custom library.

*edit 1 what do I mean by "real assemblies": I mean assemblies which are more complex and have references to non-standard-.NET libraries/assemblies


Thanks for the hint to fuslogvw.exe Hans Passant but what do you mean by "with code like this"?


okay I used fuslogvw.exe and I get two exceptions for every single dll that is referenced by the "selectedAssembly".
The first one says something like
"The binding starts in LoadFrom-context
The image owned by the system isn't searched in LoadFrom-Context"

the other logentry says that the dll referenced by the selectedAssembly couldn't be found and it tried to download it from application's base path and all directories below...but not from it's actual location...so, key question: how do I change the Load-context to LoadFrom? And why is .NET so stubborn on this? I mean the assemblies are loaded in the AppDomain, it shouldn't care about the actual location of the assembly.


okay problem solved. Here is the solution:
http://ayende.com/blog/1376/solving-the-assembly-load-context-problem

I implemented that into my existing class (removed the static-keyword and put the body of the Init method into my method), compiled it and it worked.

Thanks for your help guys.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

維他命╮ 2024-12-10 22:48:52

好的问题解决了。这是解决方案: http://ayende.com/blog/ 1376/solving-the-assemble-load-context-problem

我将其实现到我现有的类中(删除了 static 关键字并将 Init 方法的主体放入我的方法中),编译它并且它起作用了。

谢谢你们的帮助。

以防万一网站有一天不可用,这里是 ayende 的源代码

static Dictionary<string, Assembly>assemblies;   

public static void Init()
{

    assemblies = new Dictionary<string, Assembly>();

    AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{

    Assembly assembly = null;

    assemblies.TryGetValue(args.Name, out assembly);

    return assembly;

} 

static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{

    Assembly assembly = args.LoadedAssembly;
    assemblies[assembly.FullName] = assembly;
}

okay problem solved. Here is the solution: http://ayende.com/blog/1376/solving-the-assembly-load-context-problem

I implemented that into my existing class (removed the static-keyword and put the body of the Init method into my method), compiled it and it worked.

Thanks for your help guys.

just in case the website will someday be unavailable, here is the sourcecode from ayende

static Dictionary<string, Assembly>assemblies;   

public static void Init()
{

    assemblies = new Dictionary<string, Assembly>();

    AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{

    Assembly assembly = null;

    assemblies.TryGetValue(args.Name, out assembly);

    return assembly;

} 

static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{

    Assembly assembly = args.LoadedAssembly;
    assemblies[assembly.FullName] = assembly;
}
撧情箌佬 2024-12-10 22:48:52

我建议使用 Reflector 来查看您可能尚未加载的参考文献。例如,您仅加载当前程序集正在查看的引用程序集。您是否也逐一查找每个子项以找到其引用的程序集? FileNotFound 错误可能会向您指出在另一个未加载的程序集中声明的类型。

I would recommend using Reflector to see which references you may not have loaded. For instance, you are only loading the referenced assemblies that the current assembly is looking at. Do you step down through each child to find their referenced assemblies as well? The FileNotFound error is probably pointing you in the direction of a type that is declared in another assembly that isn't loaded.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文