探索根目录,AppDomainSetup
CLR解析一个程序集会在一个根目录内进行搜索,整个探索过程又称Probing,这个根目录很显然就是当前包含当前程序集的目录,当然用户可以命令CLR不仅在根目录,而且在根目录下的子目录对程序集进行搜索,那么怎样得到当前程序集(更准确的说:是当前AppDomain)的所有探索目录呢?
AppDomainSetup这个类存储着探索目录的信息,如下这个类的部分成员:
ApplicationBase: string //根目录
PrivateBinPath: string //子目录(相对形式)
PrivateBinPath保存用分号(;)分隔的多个子目录(相对形式),可以嵌套,如ApplicationBase是C:\app,PrivateBinPath是a;b;c;c\c_a;c\c_b。那么CLR在这个AppDomain载入程序集时会搜索如下目录:
- C:\app
- C:\app\a
- C:\app\b
- C:\app\c
- C:\app\c\c_a
- C:\app\c\c_b
这里我写了个函数根据AppDomainSetup类输出所有探索目录的绝对路径,这个函数在后面的例子里也会使用
static IEnumerable<string> GetAvailablePath(AppDomainSetup set)
{
if (set.ApplicationBase == null)
return Enumerable.Empty<string>();
if (set.PrivateBinPath != null)
return set.PrivateBinPath.Split(';').Select(s => Path.Combine(set.ApplicationBase, s));
return new string[] { set.ApplicationBase };
}
通过配置文件为当前程序集添加探索子目录
许多人在部署程序的时候想将一些动态链接库放在主程序目录的子目录下,就需要为主程序添加探索子目录,这样CLR才会成功加载位于子目录下的动态链接库,这个情景很常见解决方案重所周知,这里直接贴出配置文件XML,即添加一个AssemblyBinding元素。
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="sub1;sub2;sub2\sub2_1;sub2_2"/>
</assemblyBinding>
</runtime>
</configuration>
为AppDomain动态添加探索目录并加载程序集
通过AppDomainSetup可以配置一个新的AppDomain的探索目录,并用上面提到过的函数对所有可用探索目录进行输出。如下代码,将C:\app作为新的AppDomain的探索根目录,并为其添加探索子目录。在C:\app\c\c_a中保存有要加载的DLL文件mydll.dll,最后用新的AppDomain加载这个DLL文件。
static void Main()
{
//设置AppDomainSetup
AppDomainSetup appdomSetup = new AppDomainSetup()
{
ApplicationBase = @"c:\app",
PrivateBinPath = @"a;b;c;c\c_a;c\c_b"
};
AppDomain newDomain = AppDomain.CreateDomain("My Domain", null, appdomSetup);
//列举所有可用探索目录
Console.WriteLine("所有可用探索目录");
foreach (var s in GetAvailablePath(newDomain.SetupInformation))
Console.WriteLine(s); Console.WriteLine();
//动态加载mydll, mydll.dll在C:\app\c\c_a下
newDomain.Load("mydll");
//输出新AppDomain加载的程序集的信息
foreach (var ass in newDomain.GetAssemblies())
Console.WriteLine("成功加载程序集:" + ass.FullName);
Console.ReadKey();
}
static IEnumerable<string> GetAvailablePath(AppDomainSetup set)
{
if (set.ApplicationBase == null)
return Enumerable.Empty<string>();
if (set.PrivateBinPath != null)
return set.PrivateBinPath.Split(';').Select(s => Path.Combine(set.ApplicationBase, s));
return new string[] { set.ApplicationBase };
}
输出:
所有可用探索目录
c:\app\a
c:\app\b
c:\app\c
c:\app\c\c_a
c:\app\c\c_b
成功加载程序集:mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5
c561934e089
成功加载程序集:mydll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
