UPDATE:我现在有一个解决方案,我对此感到非常高兴,虽然没有解决所有我问过的问题,但确实如此。我已经更新了自己的答案以反映这一点。如何为AppDomain预加载所有已部署的程序集
原始的问题
给定一个应用程序域,也有融合(.NET程序集加载器)会探测一个给定的装配许多不同的位置。显然,我们认为这个功能是理所当然的,因为探测似乎嵌入在.Net运行时(内部方法似乎是反射加载时的入口点 - 并且我认为隐式加载可能覆盖了相同的底层算法),作为开发者,我们似乎无法获得对这些搜索路径的访问。
我的问题是,我有一个组件做了大量的动态类型解析,并且需要能够确保给定的AppDomain的所有用户部署的程序集在开始工作之前预先加载。是的,这会降低启动速度 - 但是我们从这个组件获得的好处完全超越了这一点。
我已经写过的基本加载算法如下。它为任何.dll(.exes被排除在目前)深入扫描一组文件夹,并且使用Assembly.LoadFrom加载dll,如果它的AssemblyName不能在已经加载到AppDomain中的程序集集合中找到(这是低效实现,但是它可以在以后优化):
void PreLoad(IEnumerable<string> paths)
{
foreach(path p in paths)
{
PreLoad(p);
}
}
void PreLoad(string p)
{
//all try/catch blocks are elided for brevity
string[] files = null;
files = Directory.GetFiles(p, "*.dll", SearchOption.AllDirectories);
AssemblyName a = null;
foreach (var s in files)
{
a = AssemblyName.GetAssemblyName(s);
if (!AppDomain.CurrentDomain.GetAssemblies().Any(
assembly => AssemblyName.ReferenceMatchesDefinition(
assembly.GetName(), a)))
Assembly.LoadFrom(s);
}
}
LoadFrom被使用,因为我发现,使用Load()可导致重复由Fusion被加载如果组件,当它探测为它,它没有找到一个从它期望找到它的地方加载。
所以,我现在要做的就是按照优先顺序(从最高到最低)获取Fusion搜索装配时要使用的搜索路径列表。然后我可以简单地遍历它们。
GAC与此无关,我对Fusion可能使用的任何环境驱动的固定路径不感兴趣 - 只能从AppDomain收集的包含为应用程序明确部署的程序集的那些路径感兴趣。
我第一次使用这个简单的AppDomain.BaseDirectory。这适用于服务,表单应用程序和控制台应用程序。
但是,它不适用于Asp.Net网站,因为至少有两个主要位置--AppDomain.DynamicDirectory(其中Asp.Net将其放置在动态生成的页面类和任何程序集中,即Aspx页面代码引用),然后是该站点的Bin文件夹 - 可以从AppDomain.SetupInformation.PrivateBinPath属性中发现该文件夹。
因此,现在我已经为最基本类型的应用程序开发了工作代码(Sql Server托管的应用程序域是文件系统虚拟化以来的另一个故事) - 但几天前我遇到了一个有趣的问题,不起作用:nUnit测试跑步者。
这使用了Shadow Copying(因此我的算法需要从shadow-copy drop文件夹中发现并加载它们,而不是从bin文件夹中加载),并将PrivateBinPath设置为相对于基本目录。
当然,还有一些其他托管方案可能还没有考虑过;但必须是有效的,否则Fusion会在加载程序集时窒息。
我想停止感觉并在黑客入侵时适应这些新场景 - 我想要的是,给定一个AppDomain及其设置信息,能够生成我应该扫描的这个文件夹列表为了拿起所有要加载的DLL;不管AppDomain如何设置。如果Fusion可以看到它们完全相同,那么我的代码也应该如此。
当然,如果.Net改变它的内部结构,我可能不得不改变算法 - 这只是我必须忍受的一个交叉。同样,我很高兴将SQL Server和其他类似的环境视为现在仍然不受支持的边缘案例。
任何想法!?
不是一个真正的答案,但对我来说非常有帮助这MSDN-文章:http://msdn.microsoft.com/en-us/library/yx7xezcf。 ASPX)。 而提到的Fuslogvw.exe应该有助于获得“为什么没有找到该DLL”。 – 2010-06-21 06:35:14
ralf.w:我确实想知道是否可以通过为一个不存在的程序集获取一个融合日志并解析它来查看它正在查找的所有地方来作弊。虽然它可能会起作用,但我感觉我不得不在目标盒上打开Fusion Logging(=慢);加上我会被异常编码的事实,这只是错误!感谢您的文章链接 - 也许多一点MSDN挖掘可能会给我答案... – 2010-06-21 07:18:14
我有这个问题,你愿意分享你到达的代码吗?谢谢:) – 2010-10-20 09:46:00