解决程序集,模糊方式
Posted
技术标签:
【中文标题】解决程序集,模糊方式【英文标题】:Resolving Assemblies, the fuzzy way 【发布时间】:2010-04-28 12:42:50 【问题描述】:设置如下:
纯 DotNET 类库由非托管桌面应用程序加载。类库充当插件。这个插件加载自己的小插件(所有 DotNET 类库),它通过将 dll 作为字节流读入内存来实现,然后
Assembly asm = Assembly.Load(COFF_Image);
当这些小插件引用其他 dll 时,就会出现问题。由于它们是通过内存而不是直接从磁盘加载的,因此框架通常找不到这些引用的程序集,因此无法加载它们。
我可以向我的项目添加一个 AssemblyResolver 处理程序,并且我可以看到这些引用的程序集消失了。我对在磁盘上哪里可以找到这些引用的程序集有一个相当不错的想法,但是如何确保我加载的程序集是正确的呢?
简而言之,我如何可靠地从 System.ResolveEventArgs.Name 字段转到 dll 文件路径,假设我有一个该 dll 可能隐藏的所有文件夹的列表)?
【问题讨论】:
【参考方案1】:当我过去使用它时,我们只是将文件名与具有该名称的 ResolveEventArgs.Name 部分进行了比较。如果您想确保加载完全相同的版本,我想您可以检查名称是否匹配,如果匹配,则加载程序集,然后根据 ResolveEventArgs.Name 检查程序集的全名。
类似的东西:
string name = GetAssemblyName (args); //gets just the name part of the assembly name
foreach (string searchDirectory in m_searchDirectories)
string assemblyPath = Path.Combine (executingAssemblyPath, searchDirectory);
assemblyPath = Path.Combine (assemblyPath, name + ".dll");
if (File.Exists (assemblyPath))
Assembly assembly = Assembly.LoadFrom (assemblyPath);
if (assembly.FullName == args.Name)
return assembly;
为了完整性:
private string GetAssemblyName (ResolveEventArgs args)
String name;
if (args.Name.IndexOf (",") > -1)
name = args.Name.Substring (0, args.Name.IndexOf (","));
else
name = args.Name;
return name;
【讨论】:
Sam,这不是有点浪费吗,因为它肆意加载程序集,直到找到合适的程序集? 它只加载与我们试图解析的程序集同名的 dll。当我完成这意味着它只加载我需要的 1 个 dll,但如果 dll 和程序集没有相同的名称,那么您将不得不加载每个 dll 并根据您正在寻找的名称检查程序集名称。 我想防止它污染我的 AppDomain 的唯一方法是创建另一个 AppDomain 并首先将它们加载到那里?【参考方案2】:Managed Extensibility Framework (MEF) 听起来可以解决您的所有问题。它可以扫描文件夹以定位 DLL,解决任何深度的依赖关系并管理插件组合。每个部分(或“插件”)只需声明它需要什么以及提供什么,MEF 负责接线。如果 MEF 成功驯服了 VS2010 的可扩展性野兽,那么它可以处理任何事情。
【讨论】:
【参考方案3】:AssemblyResolver 从来没有运气好过。我通常做以下三个之一:
-
要求插件没有 GAC 中没有的外部引用。如果他们讨厌,告诉他们ILMerge。
要求插件将其所有 dll 转储到已知插件目录中。将该目录中的所有程序集加载到内存中。
要求插件依赖项存在于融合探测的路径中。您可以找出 binder 在哪里寻找程序集打开融合日志(fuslogvw.exe——打开日志记录后不要忘记重新启动!)。
【讨论】:
以上是关于解决程序集,模糊方式的主要内容,如果未能解决你的问题,请参考以下文章
使用版本重定向解决以COM方式调用Excel程序集版本不一致问题
通过 EnvDTE 在 C# 中以编程方式添加项目引用(而不是程序集引用)