102 lines
5.8 KiB
Markdown
102 lines
5.8 KiB
Markdown
# 独立功能插件
|
||
|
||
`Modules/` 使用 IModule,存放商城业务模块;`Plugins/` 使用 IPlugin,存放共用 API 宿主的独立功能。
|
||
公共项目 `Core/MAX.Plugins` 不依赖商城业务或数据库库,提供:
|
||
|
||
- `IPlugin`:唯一 Id、Priority、服务注册和管道装配生命周期。
|
||
- `PluginBase`:保存插件上下文、配置校验、默认管道实现;派生类只需实现 RegisterServices,按需重写 ConfigureApplication。
|
||
- `PluginContext`:插件目录、宿主环境、隔离的 Configuration 和必需配置校验。
|
||
|
||
宿主扫描加载插件,按 Priority 降序注册,显式注册 MVC Application Parts;IModule/IStartup 与 IPlugin 分开执行,禁止同一入口同时实现两套生命周期。
|
||
|
||
## 生成和部署
|
||
|
||
在仓库根目录执行,宿主无需引用具体插件:
|
||
|
||
```powershell
|
||
dotnet build Store.API/Store.Api.csproj -c Release
|
||
dotnet build Plugins/CloudProduct/Store.CloudProduct.csproj -c Release
|
||
dotnet build Plugins/Store.ImageCache/Store.ImageCache.csproj -c Release
|
||
dotnet Bin/Store.Api.dll --contentRoot "$PWD/Bin"
|
||
```
|
||
|
||
API 输出到根目录 Bin;插件生成后自动复制到 Bin/Plugins/<项目名>/。生成过程按相对路径和 SHA-256 清理宿主已提供的重复文件;插件自己的 appsettings*.json 始终保留。
|
||
宿主后生成时也会去重;同名但内容不同的依赖保留,由加载器检查版本兼容性。
|
||
Debug/Release 共用 Bin,部署前请统一使用 Release。整体拷贝 Bin 部署,需要兼容的 .NET/ASP.NET Core 运行时。
|
||
|
||
```text
|
||
Bin/
|
||
Store.Api.dll
|
||
MAX.Plugins.dll
|
||
appsettings.json
|
||
Plugins/
|
||
Store.CloudProduct/
|
||
Store.CloudProduct.dll
|
||
Store.CloudProduct.deps.json
|
||
appsettings.json
|
||
Store.ImageCache/
|
||
Store.ImageCache.dll
|
||
Store.ImageCache.deps.json
|
||
appsettings.json
|
||
```
|
||
|
||
每个部署子目录只放一个插件入口。构建会清理重命名前的旧入口文件;其他过期依赖或旧目录需要自行清理。
|
||
插件扫描配置 Plugins:Path 默认 Plugins,相对 AppContext.BaseDirectory,也支持绝对路径;可通过 Plugins__Path 覆盖。
|
||
MSBuild 属性 StoreHostOutputPath 可覆盖生成目录,应使用以分隔符结尾的绝对路径。
|
||
插件仅启动时加载,更新后重启,不支持卸载、热更新、进程隔离或冲突依赖版本隔离。
|
||
|
||
## 配置隔离
|
||
|
||
各插件只读取自身目录,按以下顺序覆盖:
|
||
|
||
1. appsettings.json(必需)。
|
||
2. appsettings.<EnvironmentName>.json(可选,例如 appsettings.Development.json)。
|
||
3. 前缀 Plugins__<Id>__ 的环境变量,例如 Plugins__CloudProduct__Search__Url。
|
||
|
||
宿主配置、其他插件配置不会并入插件配置,插件配置也不会修改宿主 IConfiguration。
|
||
配置在启动时加载,修改后重启。缺失文件、格式错误或缺失必需项时,错误包含插件身份及上下文信息。
|
||
原有配置键保持不变;原始数据相对路径改为相对于 CloudProduct 插件目录,绝对路径不变。
|
||
|
||
插件通过 Context.Configuration 读取配置。业务服务可使用按插件 Id 注册的上下文,或在插件注册时将配置绑定到专属 Options:
|
||
|
||
```csharp
|
||
public ExampleService([FromKeyedServices("CloudProduct")] PluginContext context)
|
||
{
|
||
var url = context.RequireConfiguration("Search:Url");
|
||
}
|
||
```
|
||
|
||
业务数据库和 OpenSearch 保留在各自插件内;Hangfire、认证、日志由宿主管理。
|
||
CloudProduct 的搜索启动检查使用 BackgroundService,网络错误记录日志,不阻断 HTTP 启动。
|
||
|
||
### 宿主 Hangfire 配置
|
||
|
||
宿主通过 MAX.Framework 的 AddStoreHangfire 注册共享存储和 Worker,在认证、授权中间件之后调用 UseStoreHangfire 挂载 `/hangfire`。插件只注册自己的 Job 和定时任务。
|
||
|
||
宿主 appsettings.json 必须提供 `Hangfire:ConnectionString`、`Hangfire:Dashboard:User` 和 `Hangfire:Dashboard:Pass`。可用环境变量 `Hangfire__ConnectionString`、`Hangfire__Dashboard__User`、`Hangfire__Dashboard__Pass` 覆盖。原 `Plugins__CloudProduct__Hangfire__Dashboard__*` 配置需迁移至宿主。
|
||
|
||
初始连接指向原 CloudProduct 任务库,继续使用 `Hangfire_` 表和已有任务。部署时将实际 CloudProductConnection 对应的任务库连接填入宿主配置,保留原 Job 程序集、类型、方法和定时任务 ID。Hangfire 使用独立 FreeSql 单例,云商品业务仍使用插件的 CloudProductConnection。数据库恢复后,定时任务注册失败的实例需重启以重新注册。
|
||
|
||
## 新增插件
|
||
|
||
在 Plugins 下创建类库,引用 Core/MAX.Plugins 和需要的共享业务框架,提供有无参构造函数的 PluginBase 派生类以及唯一 Id。
|
||
提供 appsettings.json,将 appsettings*.json 设置为复制到生成和发布目录。Plugins 下的公共构建配置自动携带依赖并复制到宿主目录。
|
||
无需修改 Store.API;入口程序集名称需符合 StoreHubAppTypeFinder.cs 中的过滤规则。
|
||
|
||
如需完整独立发布产物,可分别 dotnet publish -o 到自定义目录;自定义发布目录不执行 Bin 下的共享文件去重。
|
||
|
||
## 验证
|
||
|
||
```powershell
|
||
dotnet run --project Tests/PluginLoadingSmoke -- configuration
|
||
dotnet run --project Tests/PluginLoadingSmoke -- hangfire
|
||
dotnet run --project Tests/PluginLoadingSmoke -- "$PWD/Bin/Plugins"
|
||
dotnet run --project Tests/PluginLoadingSmoke -- "$PWD/Bin/Plugins/Store.ImageCache" image
|
||
dotnet run --project Tests/PluginLoadingSmoke -- <空目录或不存在目录> empty
|
||
dotnet run --project Tests/PluginLoadingSmoke -- <缺依赖或版本冲突目录> failure
|
||
```
|
||
|
||
配置验证覆盖同名键隔离、环境文件和环境变量覆盖、必需文件和配置项缺失。
|
||
加载验证覆盖两个插件的控制器、DI、数据库服务注册和业务服务构造,不连接数据库或启动后台任务。
|
||
真实启动还需数据库和 OpenSearch;外部服务不可达应结合日志判断对应功能状态。
|