在MVC控制器中,我使用AssemblyLoadContext.Default.LoadFromAssemblyPath(pathToDll);
加载程序集。我想在运行时删除或替换给定的.dll文件。这是不可能的,因为文件没有被丢弃。有没有办法处理.dll文件?有使用AppDomain
类的解决方案,这在asp.net核心中不可用。
背景 : 用户可以上载包含给定接口实现的自定义.dll文件。用户还应该能够替换他的文件。我在控制器中使用以下代码来访问实现:
var conventions = new ConventionBuilder();
conventions
.ForTypesDerivedFrom<IPluginContract>()
.Export<IPluginContract>()
.Shared();
var configuration = new ContainerConfiguration().WithAssembliesInPath(path, conventions);
using (var container = configuration.CreateContainer())
{
var plugins = container.GetExports<IPluginContract>();
return plugins;
}
使用
public static ContainerConfiguration WithAssembliesInPath(
this ContainerConfiguration configuration,
string path, AttributedModelProvider conventions,
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
var fileNames = Directory
.GetFiles(path, "*.dll", searchOption);
List<Assembly> assemblies = new List<Assembly>();
foreach (string relativePath in fileNames)
{
Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(relativePath));
assemblies.Add(assembly);
}
configuration = configuration.WithAssemblies(assemblies, conventions);
return configuration;
}
答案 0 :(得分:1)
选项1:
尝试使用方法LoadFromStream加载dll,然后可以无例外地删除dll。
例如:
foreach (string relativePath in fileNames)
{
using (var fs = File.Open(relativePath , FileMode.Open))
{
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(fs);
assemblies.Add(assembly);
}
File.Delete(relativePath); //It doesn't throw exception
}
注意:已在Net Core 3.1上进行了测试,但可以与以前的版本一起使用。
选项2:
如果在尝试使用LoadFromStream
重新加载程序集时遇到问题,则应尝试在AssemblyLoadContext.Default.Unload()
之前调用LoadFromStream()
但是我不确定它是否可以与AssemblyLoadContext.Default
一起使用,因此,如果您仍然保留任何异常,则应创建从AssemblyLoadContext
继承并带有标记isCollectible
到true的任何类,如下所示:
public class PluginLoadContext : AssemblyLoadContext
{
public PluginLoadContext() : base(isCollectible: true)
{
}
}
代码应为:
//var pluginContext = new PluginLoadContext(); //In some place to call unload later
pluginContext.Unload();
foreach (string relativePath in fileNames)
{
using (var fs = File.Open(relativePath , FileMode.Open))
{
Assembly assembly = pluginContext.LoadFromStream(fs);
assemblies.Add(assembly);
}
File.Delete(relativePath); //It doesn't throw exception
}
选项3:
还有一个选项可以覆盖自定义PluginLoadContext
的Load方法,您只需要加载条目dll,并且您的条目dll的deps.json文件就知道了参考dll。
在此示例中,使用MemoryStream
阻止附加插件dll。
public class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath) : base(isCollectible: true)//isCollectible doesn't appear in netstandard2.1
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
//Using MemoryStream to prevent attach dll to this .exe
MemoryStream ms = new MemoryStream();
using (var fs = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
fs.CopyTo(ms);
}
ms.Position = 0;
return LoadFromStream(ms);
}
return null;
}
}
然后,您可以像这样加载条目插件dll。
var dllPath = "<path to your entry dll>" // dll and deps.json file together .
var pc = new PluginLoadContext(dllPath);
var assembly = pc.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(dllPath)));
//You can load a reference dll too if you need it
var referenceAssembly = pc.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension("<path of reference dll>")));
参考: https://docs.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support#load-plugins
答案 1 :(得分:0)
当你将dll加载到你的应用程序域时,这个dll在appDomain被销毁之前是不是免费的(即你的进程被停止)没有处理dll。
有关如何达到所需功能的参考,请查看已经回答的这些问题:
答案 2 :(得分:0)
这听起来与(托管扩展框架)非常相似。它允许注入DLL,还有助于管理生命周期。
示例:
public static class MefInjection
{
private static CompositionContainer mycontainer;
public static CompositionContainer MyContainer
{
get
{
if (mycontainer == null)
{
var catalog =
new DirectoryCatalog(".", "MyMEFProject.*");
mycontainer = new CompositionContainer(catalog);
}
return mycontainer;
}
}
}
前面的代码将从“ MyMEFProject”开始的同一目录中的所有程序集中获取所有导出的值。然后,您可以使用mycontainer
来获取已加载的DLL的功能。