你这个需求「ASP.NET Core 插件开发 + DLL 热加载」本质上就是做一个 可扩展插件系统,类似于 CMS、框架里那种“外部程序集即插即用”,并且支持在运行时加载/卸载 DLL,不重启应用。下面我帮你整理下第二阶段(进阶版)的思路和方案。


一、插件系统的核心问题

  1. 插件发现:如何找到可用的 DLL(比如放在 /plugins 文件夹下)。
  2. 插件隔离:如何避免插件之间类型冲突,如何防止卸载失败(.NET Core 中 Assembly 默认不能卸载)。
  3. 插件加载:如何把 DLL 动态加载到 ASP.NET Core 容器里。
  4. 热更新:如何替换旧 DLL,加载新 DLL,并能释放旧 DLL 占用。

二、ASP.NET Core 插件热加载实现路径

1. 使用 AssemblyLoadContext

  • 在 .NET Core 里,默认的 AssemblyLoadContext (ALC) 无法卸载程序集。
  • 解决方案:使用 自定义 ALC(可卸载),这样卸载插件时整个 ALC 被回收,DLL 文件才能释放。

示例代码:

public class PluginLoadContext : AssemblyLoadContext
{
    private AssemblyDependencyResolver _resolver;

    public PluginLoadContext(string pluginPath) : base(isCollectible: true) 
    {
        _resolver = new AssemblyDependencyResolver(pluginPath);
    }

    protected override Assembly Load(AssemblyName assemblyName)
    {
        string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
        if (assemblyPath != null)
        {
            return LoadFromAssemblyPath(assemblyPath);
        }
        return null;
    }
}


2. 插件接口定义

定义一个插件标准接口,插件必须实现:

public interface IPlugin
{
    string Name { get; }
    Task ExecuteAsync(HttpContext context);
}


3. 动态加载插件

加载插件:

public class PluginManager
{
    private readonly Dictionary<string, (PluginLoadContext, IPlugin)> _plugins = new();

    public void LoadPlugin(string pluginDllPath)
    {
        var loadContext = new PluginLoadContext(pluginDllPath);
        var assembly = loadContext.LoadFromAssemblyPath(pluginDllPath);

        var pluginType = assembly.GetTypes()
            .FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract);

        if (pluginType != null)
        {
            var plugin = (IPlugin)Activator.CreateInstance(pluginType);
            _plugins[plugin.Name] = (loadContext, plugin);
        }
    }

    public void UnloadPlugin(string name)
    {
        if (_plugins.TryGetValue(name, out var entry))
        {
            _plugins.Remove(name);
            entry.Item1.Unload(); // 卸载 ALC
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }

    public async Task ExecutePlugin(string name, HttpContext context)
    {
        if (_plugins.TryGetValue(name, out var entry))
        {
            await entry.Item2.ExecuteAsync(context);
        }
    }
}


4. ASP.NET Core 集成

在 Startup.cs / Program.cs 里挂载路由:

app.Map("/plugin/{name}", builder =>
{
    builder.Run(async ctx =>
    {
        var name = ctx.Request.RouteValues["name"]?.ToString();
        await pluginManager.ExecutePlugin(name, ctx);
    });
});


三、热加载流程

  1. 把新的插件 DLL 放到 /plugins 目录。
  2. 调用 pluginManager.LoadPlugin(path) 动态加载。
  3. 如果要替换旧版本:
    • 调用 pluginManager.UnloadPlugin(oldName) 卸载旧的 ALC。
    • 再调用 pluginManager.LoadPlugin(newPath) 加载新 DLL。

这样就能做到 不重启 ASP.NET Core 服务的 DLL 热加载与替换


四、进阶优化(二阶段要点)

  • 🔹 加入 文件监控FileSystemWatcher),自动检测 /plugins 文件夹 DLL 变动 → 自动卸载/加载。
  • 🔹 插件生命周期:OnLoadOnUnload 回调。
  • 🔹 日志隔离:插件内异常要捕获,不能影响主系统。
  • 🔹 安全策略:可限制插件只调用某些 API,避免恶意代码。

👉 问你一下:你是打算做

  • Web API 插件系统(比如模块化接口扩展)
  • 还是 业务规则插件系统(像规则引擎,热更新业务逻辑)

我可以根据你的用途帮你写一个 完整 demo(含 Program.cs、插件 DLL、热加载逻辑)

要不要我直接帮你写一个 最小可运行的 ASP.NET Core 插件热加载 Demo