为.Net项目添加动态库加载路径

本文分别基于.Net Framework和.Net Core的WPF应用程序为例,来说明如何为.Net项目添加自定义动态库加载路径。本文基于.Net Core创建WPF时,使用了.Net5作为目标框架。

1、.Net Framework

在基于.Net Framework的WPF项目中,直接在配置文件(App.config)中添加runtime节点即可。

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <!-- 指定加载程序集时公共语言运行时搜索的子目录, 
         其中privatePath是相对于*.exe.config文件的相对路径,
         多个文件夹以分号分隔。-->
    <probing privatePath="Libs\Lib1;Libs\Lib2"/>
  </assemblyBinding>
</runtime>

2、.Net5

在基于.Net5的WPF项目中,使用privatePath已经不能够实现指定文件夹程序集的加载了,这大概时因为在.Net5中,程序集的加载依赖于应用程序的.deps.json文件,而privatePath指定的文件夹中的程序集不会被添加到.deps.json文件中。

基于"<probing privatePath="..." /> doesn't work in .Net 5.0",在项目文件(配置文件中应该也可以)设置动态库加载路径,然后基于AssemblyLoadContext类的Resolving事件,在应用程序查找未知类型时加载配置文件中的动态库。

(1)在.csproj文件中设置动态库路径

<ItemGroup>
  <RuntimeHostConfigurationOption Include="SubdirectoriesToProbe" Value="Plugins" />
</ItemGroup>

(2)在代码中实现类型动态加载

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        //加载程序集事件
        AssemblyLoadContext.Default.Resolving += ResolveAssembly;

        base.OnStartup(e);
    }
    
    //加载指定位置程序集
    private static Assembly ResolveAssembly(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName)
    {
        var probeSetting = AppContext.GetData("SubdirectoriesToProbe") as string;
        if (string.IsNullOrEmpty(probeSetting))
        {
            return null;
        }

        foreach (var subDirectory in probeSetting.Split(';'))
        {
            var pathMaybe = Path.Combine(AppContext.BaseDirectory, subDirectory, $"{assemblyName.Name}.dll");
            if (File.Exists(pathMaybe))
            {
                return assemblyLoadContext.LoadFromAssemblyPath(pathMaybe);
            }
        }

        return null;
    }
}
posted @ 2021-08-03 12:56  xhubobo  阅读(1293)  评论(0编辑  收藏  举报