这确保每个插件都在其自己的上下文中加载,以便插件可以成功地使用插件之间具有冲突版本的程序集。 我的插件中的一个使用我不允许重新分配的第三方DLL,因此用户需要自己下载此(以及Aquire a使用使用许可证)。 如果这是一个定期在Windows/Linux中运行的独立应用程序,这不会引起任何问题,因为我可以指示用户将DLL直接复制到与插件的同一文件夹中。 我希望将其创建为公共Docker映像,该图像可防止用户直接复制到插件文件夹中。
我最初的想法是将第三方DLL放入将映射到docker容器中的“数据”文件夹中(即将写入日志)。在项目文件中引用程序集工作正常:
<ItemGroup>
<Reference Include="Some3rdParty">
<HintPath>..\..\data\lib\Some3rdParty.dll</HintPath>
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</Reference>
</ItemGroup>
所有的内容都可以很好地编译。
但是,当我的主要应用程序试图加载插件组件时,它抱怨它找不到它,这并不奇怪,因为构建解决方案时没有复制到插件文件夹(这是正确的,因为我无法重新分发它):
System.Reflection.ReflectionTypeloadexception:无法加载一种或多种请求类型。
因此,问题是:如何将插件引用作为第三方组件,并从完全不同的文件夹中加载它,而我的主应用程序可以加载插件而没有错误?
Microsoft文章指示您创建一个看起来像这样的
Some3rdParty.dll
:
PluginLoadContext
class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (libraryPath != null)
{
return LoadUnmanagedDllFromPath(libraryPath);
}
return IntPtr.Zero;
}
}
的构造函数加载到的构造函数,以便如果初始
List<string>
PluginLoadContext
失败,则可以尝试其中之一:
I已经从插件文件夹中读取
public class PluginLoadContext(string pluginPath, List<string> additionalAssemblyFolders) : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
private List<string> _additionalAssemblyFolders;
public PluginLoadContext(string pluginPath, List<string> additionalAssemblyFolders)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
_additionalAssemblyFolders = additionalAssemblyFolders;
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}
if (additionalAssemblyFolders == null)
{
return null;
}
foreach (string assemblyFolder in _additionalAssemblyFolders)
{
string potentialAssemblyPath = Path.Combine(assemblyFolder, $"{assemblyName.Name}.dll");
FileInfo fi = new(potentialAssemblyPath);
if (fi.Exists)
{
return LoadFromAssemblyPath(fi.FullName);
}
}
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (libraryPath != null)
{
return LoadUnmanagedDllFromPath(libraryPath);
}
foreach (string assemblyFolder in additionalAssemblyFolders)
{
string potentialAssemblyPath = Path.Combine(assemblyFolder, $"{unmanagedDllName}.dll");
FileInfo fi = new(potentialAssemblyPath);
if (fi.Exists)
{
return LoadUnmanagedDllFromPath(fi.FullName);
}
}
return IntPtr.Zero;
}
}
,所以现在我可以在我的appsettings.json
列表中添加一个清单,然后将其发送到创建的位置。