在 ASP.NET Core 里实现 插件式开发 + DLL 热加载,本质是:
- 把功能模块(插件)编译成独立的 .dll;
- 运行时动态加载这些程序集(Assembly);
- 提供隔离、卸载、更新能力,避免内存泄露或锁文件。
🔑 核心要点
1. 插件目录
准备一个文件夹,例如:Plugins/
,存放编译好的插件 DLL。
2. 插件接口约定
所有插件遵循一个接口或抽象基类,便于主程序调用:
public interface IPlugin
{
string Name { get; }
string Execute(string input);
}
插件示例(单独编译成 DLL):
public class HelloPlugin : IPlugin
{
public string Name => "HelloPlugin";
public string Execute(string input)
{
return $"Hello, {input}!";
}
}
3. 动态加载插件
ASP.NET Core 中常见两种方式:
✅ AssemblyLoadContext(推荐)
支持卸载,适合“热加载”场景。
using System.Reflection;
using System.Runtime.Loader;
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;
}
}
加载插件:
public class PluginManager
{
private readonly List<IPlugin> _plugins = new();
private PluginLoadContext _context;
public void LoadPlugin(string pluginPath)
{
_context = new PluginLoadContext(pluginPath);
var assembly = _context.LoadFromAssemblyPath(pluginPath);
var types = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);
foreach (var type in types)
{
var plugin = (IPlugin)Activator.CreateInstance(type);
_plugins.Add(plugin);
}
}
public IEnumerable<IPlugin> GetPlugins() => _plugins;
public void Unload()
{
_context.Unload();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
4. ASP.NET Core 集成
可以做成一个 API 控制器,用于调用/热加载:
[ApiController]
[Route("api/plugins")]
public class PluginController : ControllerBase
{
private readonly PluginManager _pluginManager;
public PluginController(PluginManager pluginManager)
{
_pluginManager = pluginManager;
}
[HttpPost("load")]
public IActionResult Load([FromBody] string path)
{
_pluginManager.LoadPlugin(path);
return Ok("Plugin loaded.");
}
[HttpGet("exec")]
public IActionResult Exec(string input)
{
var results = _pluginManager.GetPlugins().Select(p => p.Execute(input));
return Ok(results);
}
[HttpPost("unload")]
public IActionResult Unload()
{
_pluginManager.Unload();
return Ok("Plugin unloaded.");
}
}
⚠️ 注意事项
- 程序集锁定:.NET Framework 时代会锁 DLL,.NET Core 用
AssemblyLoadContext
解决。 - 依赖冲突:插件依赖的包最好和主程序隔离,可用独立目录。
- 安全性:加载外部 DLL 要小心执行恶意代码,可加签名校验。
- 性能优化:频繁加载卸载要考虑内存清理,调用
GC.Collect()
强制释放。
👉 总结:
在 ASP.NET Core 里做 DLL 热加载插件系统,推荐用 AssemblyLoadContext 实现插件隔离和卸载。核心就是 约定接口 + 插件目录 + 动态加载 + 管理器控制。
要不要我帮你写一个 完整的 Demo 项目结构(包含主程序 + 插件工程 + 控制器接口),方便你直接跑?
发表回复