ASP.NET Boilerplate 插件(PlugIn)开发实战:以 DatabaseMaintainer 插件定时清理审计日志

发布时间:2026/9/23 22:50:02
ASP.NET Boilerplate 插件(PlugIn)开发实战:以 DatabaseMaintainer 插件定时清理审计日志 后端Web框架依赖注入认证鉴权【免费下载链接】aspnetboilerplateASP.NET Boilerplate - Web Application Framework项目地址https://gitcode.com/gh_mirrors/as/aspnetboilerplate点击查看免费下载本篇技术指南以 ASP.NET BoilerplateABP框架的插件机制为核心完整演示如何从零创建一个名为DatabaseMaintainer的插件类库通过继承AbpModule定义插件模块、借助PeriodicBackgroundWorkerBase实现定时清理审计日志的后台工作器并将其动态加载进 ASP.NET Core 应用Startup.cs中通过PlugInSources.AddFolder挂载。读完本文你将掌握 ABP 插件项目的搭建、构建产物部署、运行时装载原理以及仓库源码中IPlugInSource系列实现背后的加载与装配机制可直接复用到日志清理、定时任务、模块化扩展等真实场景。插件机制概览ABP 如何发现并加载一个插件ABP 的插件PlugIn本质上是独立的程序集 继承AbpModule的模块类。应用启动时ABP 会扫描插件来源PlugIn Source把插件程序集里的模块类型当作普通模块一样纳入模块依赖图统一经历PreInitialize→Initialize→PostInitialize生命周期模块生命周期详见 Module-System.md。从源码结构看这套机制由src/Abp/PlugIns/目录下的类型协作完成类型职责IPlugInSource插件来源抽象暴露GetAssemblies()与GetModules()两个方法IPlugInSource.csFolderPlugInSource扫描指定文件夹下的 DLL/EXE 程序集FolderPlugInSource.csAssemblyFileListPlugInSource直接按文件路径列表加载程序集AssemblyFileListPlugInSource.csPlugInTypeListSource直接以模块Type列表声明插件PlugInTypeListSource.csPlugInSourceList插件来源集合聚合去重所有程序集与模块PlugInSourceList.csAbpPlugInManager持有PlugInSources集合并注册AppDomain.AssemblyResolve兜底解析AbpPlugInManager.cs运行时装配链可以概括为应用在ConfigureServices中通过services.AddAbpTStartupModule(options ...)传入options.PlugInSources扩展方法见 AbpServiceCollectionExtensions.csAbpBootstrapperOptions.PlugInSources定义见 AbpBootstrapperOptions.cs。AbpBootstrapper.Initialize()把options.PlugInSources合并进AbpPlugInManager.PlugInSourcesAbpBootstrapper.cs。AbpModuleManager.Initialize递归查找依赖模块后调用_abpPlugInManager.PlugInSources.GetAllModules()收集插件模块类型并标记为插件模块参与创建与启动AbpModuleManager.cs。其中什么类型算一个 ABP 模块由AbpModule.IsAbpModule(Type)判定必须是非抽象、非泛型、继承AbpModule的类AbpModule.cs。FolderPlugInSource在GetModules()中正是用这个方法逐个类型过滤FolderPlugInSource.cs。创建插件搭建 DatabaseMaintainer 类库项目新建类库并引入必要 NuGet 包在 IDE 中新建一个类库Class Library项目例如名为DatabaseMaintainer注意本插件需要引用Abp与Abp.ZeroCore两个 NuGet 包。Abp.ZeroCore提供模块零Module Zero的多租户、审计日志等基础设施其AbpZeroCoreModule定义见 AbpZeroCoreModule.cs因为我们要操作的是 Module Zero 的AuditLog实体。编写插件模块类插件必须有一个继承AbpModule的模块类并用[DependsOn]声明它依赖AbpZeroCoreModule这样模块零的实体映射、工作单元、审计基础设施都会随插件一并加载using System.Reflection; using Abp.Modules; using Abp.Threading.BackgroundWorkers; using Abp.Zero; namespace DatabaseMaintainer { [DependsOn(typeof(AbpZeroCoreModule))] public class DatabaseMaintainerModule : AbpModule { public override void Initialize() { // 按约定注册当前程序集中的所有类应用服务、仓储、工作器等 IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } public override void PostInitialize() { // 应用启动完成后把后台工作器注册进全局后台工作器管理器 var workManager IocManager.ResolveIBackgroundWorkerManager(); workManager.Add(IocManager.ResolveDeleteOldAuditLogsWorker()); } } }两个重写方法的分工Initialize()通过IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly())按 ABP 约定注册程序集中的类型单例、瞬态、ISingletonDependency等这是让后台工作器可被IocManager.Resolve的前提。PostInitialize()在所有模块初始化完成、应用即将对外服务时把工作器加入IBackgroundWorkerManager。这正是 ABP 官方模块自身的惯用模式——AbpZeroCoreModule也是在PostInitialize中把UserTokenExpirationWorker注册进工作器管理器AbpZeroCoreModule.cs我们的插件模块与之一致。BackgroundWorkerManager的Add方法会记录工作器若管理器已在运行状态则立即Start()BackgroundWorkerManager.cs。编写后台工作器DeleteOldAuditLogsWorker插件要完成的核心业务是在给定周期内删除审计日志。这里采用PeriodicBackgroundWorkerBase——一个内置周期计时器的后台工作器基类周期计时器细节见 Background-Jobs-And-Workers.mdusing System; using Abp.Auditing; using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Threading.BackgroundWorkers; using Abp.Threading.Timers; using Abp.Timing; namespace DatabaseMaintainer { public class DeleteOldAuditLogsWorker : PeriodicBackgroundWorkerBase, ISingletonDependency { private readonly IRepositoryAuditLog, long _auditLogRepository; public DeleteOldAuditLogsWorker(AbpTimer timer, IRepositoryAuditLog, long auditLogRepository) : base(timer) { _auditLogRepository auditLogRepository; Timer.Period 5000; // 周期单位毫秒这里即每 5 秒执行一次 } [UnitOfWork] protected override void DoWork() { Logger.Info(---------------- DeleteOldAuditLogsWorker is working ----------------); using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant)) { var fiveMinutesAgo Clock.Now.Subtract(TimeSpan.FromMinutes(5)); _auditLogRepository.Delete(log log.ExecutionTime fiveMinutesAgo); CurrentUnitOfWork.SaveChanges(); } } } }要点逐项拆解基类与依赖注入PeriodicBackgroundWorkerBase在构造时订阅AbpTimer.Elapsed事件Start()启动计时器、每次触发调用抽象方法DoWork()异常会被捕获并记录为Logger.WarnPeriodicBackgroundWorkerBase.cs。AbpTimer.Period以毫秒为单位默认不立即触发RunOnStart默认falseAbpTimer.cs。声明ISingletonDependency使工作器在插件程序集中按约定注册为单例可被模块PostInitialize安全地Resolve出来。仓库注入IRepositoryAuditLog, long是模块零针对AuditLog实体的标准仓储。AuditLog映射到表AbpAbpAuditLogs[Table(AbpAuditLogs)]实现IMayHaveTenant记录了TenantId、UserId、ServiceName、MethodName、Parameters、ExecutionTime、ExecutionDuration、Exception等审计字段AuditLog.cs更多审计机制见 Audit-Logging.md。关闭租户过滤器AuditLog实现IMayHaveTenant默认受MayHaveTenant数据过滤器约束——在多租户环境中未关闭过滤器时只能看到当前租户的数据。这里用CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant)临时关闭该过滤器常量定义见 AbpDataFilters.cs从而在系统级任务中跨租户统一清理日志过滤器机制详见 Multi-Tenancy.md。删除条件示例代码删除ExecutionTime fiveMinutesAgo的记录即最近 5 分钟内的日志。如果你的意图是删除超过 5 分钟前的旧日志请把条件改为log.ExecutionTime fiveMinutesAgo——清理类任务的通常语义是后者请按业务需要选择。工作单元[UnitOfWork]特性让DoWork在独立工作单元中执行配合CurrentUnitOfWork.SaveChanges()显式提交删除CurrentUnitOfWork由 BackgroundWorkerBase.cs 提供。完成后解决方案结构如下插件类库 应用项目并存构建插件用Release 配置构建插件项目。构建成功后DatabaseMaintainer.dll会生成在DatabaseMaintainer\DatabaseMaintainer\bin\Release\net5.0目录下。说明输出目录中的目标框架名如net5.0取决于插件项目的TargetFramework。插件程序集的目标框架应与宿主应用兼容——例如仓库自带的插件 Demo 项目AbpAspNetCoreDemo.PlugIn目标框架为net9.0其输出路径可从 Startup.cs 中看到请据此调整你项目中实际的框架版本目录。将插件加载进应用在 Startup.cs 中注册插件来源以下示例从wwwroot目录加载插件你也可以把插件目录换成任意路径。需要在目标应用MVC 或 Host 项目的Startup.cs的ConfigureServices中向AddAbp的options追加一行options.PlugInSources.AddFolder(Path.Combine(_hostingEnvironment.WebRootPath, Plugins), SearchOption.AllDirectories);完整的Startup.cs形态如下原文档中的多语句options委托整理为块语法与仓库 Demo 的写法一致见 Startup.cspublic class Startup { private readonly IHostingEnvironment _hostingEnvironment; private readonly IConfigurationRoot _appConfiguration; public Startup(IHostingEnvironment env) { _hostingEnvironment env; _appConfiguration env.GetAppConfiguration(); } public IServiceProvider ConfigureServices(IServiceCollection services) { ... // Configure Abp and Dependency Injection return services.AddAbpAbpProjectNameWebMvcModule(options { // Configure Log4Net logging options.IocManager.IocContainer.AddFacilityLoggingFacility( f f.UseAbpLog4Net().WithConfig(log4net.config) ); // Add plugin source: scan all DLLs under wwwroot/Plugins recursively options.PlugInSources.AddFolder( Path.Combine(_hostingEnvironment.WebRootPath, Plugins), SearchOption.AllDirectories ); }); } ... }关键 API 说明PlugInSources.AddFolder(folder, searchOption)是PlugInSourceList的扩展方法内部创建FolderPlugInSourcePlugInSourceListExtensions.cs。SearchOption.AllDirectories表示递归扫描子目录FolderPlugInSource默认只扫描顶层SearchOption.TopDirectoryOnly构造参数可覆盖FolderPlugInSource.cs。底层扫描逻辑AssemblyHelper.GetAllAssembliesInFolder只收集*.dll与*.exe并逐个Assembly.LoadFile加载AssemblyHelper.cs。除文件夹外还有PlugInSourceList.AddTypeList(params Type[])扩展方法PlugInSourceListExtensions.cs以及直接按 DLL 路径加载的AssemblyFileListPlugInSource——仓库 Demo 应用正是用它在Startup.cs中加载AbpAspNetCoreDemo.PlugIn.dllStartup.cs可作为不依赖wwwroot布局的替代方案。部署插件 DLL把构建出的DatabaseMaintainer.dll复制到应用的.Mvc/wwwroot/Plugins目录由于使用了SearchOption.AllDirectories插件 DLL 放在Plugins下的任意子目录也能被扫描到。运行应用并验证直接运行应用打开应用的日志文件如Logs.txt查看输出。若一切正常你应当能看到工作器周期性打印的日志日志中反复出现DeleteOldAuditLogsWorker is working即代表插件已被成功加载、DatabaseMaintainerModule已完成PostInitialize、后台工作器已按 5 秒周期开始执行。此时配合数据库查询AbpAuditLogs表即可确认删除逻辑是否符合预期。进阶插件内提供控制器与嵌入视图仓库自带 Demotest/aspnet-core-demo/AbpAspNetCoreDemo.PlugIn展示了更完整的插件形态——插件不仅能挂后台任务还能携带 MVC 控制器与嵌入视图插件模块AbpAspNetCoreDemoPlugInModule依赖AbpAspNetCoreModule在PreInitialize中通过Configuration.EmbeddedResources.Sources.Add(new EmbeddedResourceSet(...))把插件程序集内的Views注册为嵌入资源并在Initialize中RegisterAssemblyByConventionAbpAspNetCoreDemoPlugInModule.cs。插件程序集内含Controllers/BlogController.cs与Views/Blog/下的Index.cshtml、Index.css、Index.js随插件 DLL 一起被宿主应用发现并渲染。这印证了插件机制的应用范围远超定时任务在模块零与 ASP.NET Core 集成的基础上插件可以承载完整的功能页签控制器 视图 静态资源。嵌入资源的完整配置方式见 Embedded-Resource-Files.md控制器集成见 MVC-Controllers.md。小结与关键源码索引围绕本文内容可继续深入阅读的仓库源码与文档关注点位置插件来源抽象与三种实现src/Abp/PlugIns/插件装配进启动流程AbpBootstrapper.cs、AbpModuleManager.cs模块判定规则AbpModule.cs周期后台工作器与计时器PeriodicBackgroundWorkerBase.cs、AbpTimer.cs审计日志实体AuditLog.cs多租户数据过滤器AbpDataFilters.cs插件 Demo控制器 嵌入视图AbpAspNetCoreDemo.PlugIn 与 宿主 Startup.cs关联概念文档Module-System.md、Background-Jobs-And-Workers.md、Audit-Logging.md、Multi-Tenancy.md整体来看ABP 插件机制的价值在于按程序集边界拆分功能模块并在不修改宿主代码的前提下完成模块注册、依赖注入与后台任务挂载。把DatabaseMaintainerModule替换成你自己的业务模块重复模块类 RegisterAssemblyByConventionPlugInSources.AddFolder三步即可把任何独立功能以插件形式交付到 ABP 应用中。赞分享后端Web框架依赖注入认证鉴权【免费下载链接】aspnetboilerplateASP.NET Boilerplate - Web Application Framework项目地址https://gitcode.com/gh_mirrors/as/aspnetboilerplate点击查看免费下载相关推荐baoyu-skills 幻灯片技能中的 Vintage 复古纸张样式设计规范、色板体系与提示词工程实战baoyu skills 幻灯片技能中的 Vintage 复古纸张样式设计规范、色板体系与提示词工程实战 baoyu slide deck 是 baoyu sAI 技能AI 插件Eclipse Theia 无头插件Headless Plugin与自定义插件 API 实战以 plugin-gotd 示例插件为例Eclipse Theia 无头插件Headless Plugin与自定义插件 API 实战以 plugin gotd 示例插件为例 本篇技术指南围绕 EIDE代码编辑器开发工具前端桌面应用插件系统后端AI 应用emdash-cms/plugin-audit-logEmDash CMS 内容审计日志插件完整指南emdash cms/plugin audit logEmDash CMS 内容审计日志插件完整指南 本指南以 emdash cms/plugin audCMS后端前端插件系统上一篇Reticulum MeshChat 开发指南从源码构建到自定义功能扩展下一篇堆利用入门从 Exploitarium libssh2 publickey PoC 学任意 free 到 calc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考