首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AssemblyLoadContext Dispose .dll

AssemblyLoadContext Dispose .dll
EN

Stack Overflow用户
提问于 2016-09-08 05:15:56
回答 3查看 2.4K关注 0票数 1

在MVC控制器中,我使用AssemblyLoadContext.Default.LoadFromAssemblyPath(pathToDll);加载程序集。我希望在运行时删除或替换给定的.dll文件。这是不可能的,因为文件没有被释放。有任何方法来释放.dll文件吗?有些解决方案使用AppDomain类,这在asp.net核心中是不可用的。

后台:用户可以上传一个自定义.dll文件,其中包含给定接口的实现。用户还应该能够替换他的文件。我在控制器中使用以下代码来访问实现:

代码语言:javascript
复制
    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;
    }

使用

代码语言:javascript
复制
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;
}
EN

回答 3

Stack Overflow用户

发布于 2020-05-04 01:32:02

选项1:

尝试用方法LoadFromStream加载dll,然后可以毫无例外地删除dll。

例如:

代码语言:javascript
复制
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
}

备注:使用NetCore3.1进行测试,但可以使用以前的版本。

备选方案2:

如果您在尝试用LoadFromStream重新加载程序集时遇到问题,应该尝试在AssemblyLoadContext.Default.Unload()之前调用LoadFromStream()

但我不确定它是否适用于AssemblyLoadContext.Default,因此,如果仍然保留任何异常,则应该创建从AssemblyLoadContext继承的任何带有标志isCollectible的类,如下所示:

代码语言:javascript
复制
 public class PluginLoadContext : AssemblyLoadContext
 {
     public PluginLoadContext() : base(isCollectible: true)
     {
     }
 }

守则应是:

代码语言:javascript
复制
//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。

代码语言:javascript
复制
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。

代码语言:javascript
复制
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://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support#load-plugins

票数 3
EN

Stack Overflow用户

发布于 2016-09-08 05:36:08

当您将dll加载到应用程序域中时,在销毁appDomain (即进程停止)之前,此dll是不空闲的,因此无法对dll进行处理。

关于如何达到您想要的功能的参考,请查看已经回答的以下问题:

票数 0
EN

Stack Overflow用户

发布于 2020-05-04 22:52:21

这听起来非常类似于MEF (托管扩展框架)。它允许注入DLL,也有助于管理生命周期。

示例:

代码语言:javascript
复制
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的功能。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39383040

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档