home..

.net的动态库加载(assemlyprobing)

config

一般来说,编译一个.NET的程序,会生成以下五个文件

|-- Program.exe
|-- Program.dll
|-- Program.runtimeconfig.json
|-- Program.deps.json
|-- Program.pdb

其中,Program.exe只是一个壳子,真正的二进制程序内容在Program.dll中。
Program.dll的.NET Runtime依赖库都可以在系统默认的环境变量PATH 获得,或者添加自定义路径到DOTNET_ROOT的环境变量中。

以上都是.NET Runtime依赖库,但是如果我有一个自己的plugin project作为Program.dll的依赖库呢?

最简单的做法,就是把生成的Plugin.dll放在与Program.dll同一目录下,so fa so good.

|-- Program.exe
|-- Program.dll
|-- Program.runtimeconfig.json
|-- Program.deps.json
|-- Program.pdb
|-- Plugin.dll

但是当我的plugin依赖越来越多,需要更好的组织目录架构,将所有plugin放在同一目录下,这时候Program.dll还能找到它的依赖吗?

|-- Program.exe
|-- Program.dll
|-- Program.runtimeconfig.json
|-- Program.deps.json
|-- Program.pdb
|-- plugins
    |-- Plugin1.dll
    |-- Plugin2.dll
    |-- Plugin3.dll

.Net Framework时代,有一项配置,是app.config,里面可以添加子目录为搜索路径,但是在.NET时代,已经不再respect app.config了。

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
    <probing privatePath="plugins"/>  
</assemblyBinding>  

微软提供了.runtimeconfig.json里的additionalAssemblyPaths属性,看名字很像是可以代替app.configprivatePath选项,但是实际上在json文件添加以下属性值后,发现根本不起作用。

"additionalAssemblyPaths": [
    "plugins"
]

如果这时候使用 COREHOST_TRACE=1 来打印搜索依赖库的全过程的话,你会发现,additionalAssemblyPaths实际上是起作用了,只是它的工作原理和多数人想象的有所不同。

它搜索的路径,不是.\plugins\Plugin1.dll,而是.\plugins\Plugin1\1.0.0\Plugin1.dll!它会自动补充一个AssemblyNameAssemblyVersion

这个解决方案,就是在.deps.json里,找到依赖对应的term,然后添加"path": ".",如下图。

"libraries": {
    "Plugin1": {
        "path": "."
},

All DONE!

BTW: .runtimeconfig.json是可以在project里添加模板的,模板中添加"additionalAssemblyPaths"属性,就不需要每次编译完成后手动修改了。

但是.deps.json确实是没找到什么模板,所以必须要借助外力来修改"path": "."。我在post build event里添加了一个脚本,解析.deps.json,找到需要添加的地方,把"path": "."插进去即可。


The source code for this article can be found here. If you find any errors or have any comments, please click on the link to raise an issue in the corresponding GitHub repo.

© 2024 wanmyj   •  Powered by Soopr   •  Theme  Moonwalk