GeneralUpdate.Extension
命名空间: GeneralUpdate.Extension | 主要入口: GeneralExtensionHost(实现 IExtensionHost) | NuGet 包: GeneralUpdate.Extension
1. 组件简介
1.1 组件概述
GeneralUpdate.Extension 是面向 .NET 应用的扩展管理组件,设计目标是让宿主程序具备类似 VS Code 的扩展生态能力:从远程服务查询扩展、下载扩展包、安装或更新到本地目录,并在这个过程中处理版本兼容、平台匹配、依赖扩展、SHA256 校验、失败回滚和事件通知。
它适合把主程序和可选能力拆开发布的场景,例如报表、认证、行业插件、客户定制模块、脚本执行器等。主程序只需要集成 GeneralExtensionHost,扩展包可以独立发布、独立更新。
核心能力:
| 能力 | 说明 |
|---|---|
| 扩展查询 | 通过服务端 API 分页查询可用扩展,支持名称、发布者、分类、平台等筛选条件 |
| 一键更新 | UpdateExtensionAsync 串起查询→兼容性检查→平台检查→依赖递归安装→下载→SHA256 校验→安装→catalog 更新 |
| 安全安装 | Zip Slip 路径穿越防护、安装前备份、失败自动回滚到旧版本 |
| 批量更新 | UpdateExtensionsAsync 按顺序批量处理多个扩展,返回每个扩展的成功/失败结果 |
| 版本兼容性 | MinHostVersion ≤ HostVersion ≤ MaxHostVersion 范围内才允许安装 |
| 平台匹配 | [Flags] TargetPlatform 位运算判断扩展是否支持当前 OS |
| 依赖解析 | 拓扑排序依赖树,检测循环依赖,递归安装未安装的依赖扩展 |
| 断点续传 | 下载支持 HTTP Range,已存在部分文件时从断点继续 |
| 本地 Catalog | 每个扩展独立 manifest.json,原子写入(.tmp → 重命名),支持持久化和加载 |
| 生命周期钩子 | 安装前后、激活/停用前后、卸载前后的业务逻辑注入 |
| 自动更新策略 | SetGlobalAutoUpdate / SetAutoUpdate 控制全局或单扩展的自动更新开关 |
| DI 集成 | ExtensionHostBuilder 注册默认服务,所有服务均可通过 DI 替换 |
解决的业务痛点:
- 主程序体积膨胀,需要把非核心功能拆成可独立更新的扩展
- 不同客户需要不同功能组合,扩展生态可以实现按需安装
- 扩展之间有依赖关系,需要自动管理依赖的安装和版本兼容性
- 需要统一的扩展管理框架减少重复开发
业务使用场景:
- IDE 类应用的插件市场
- 企业 ERP/CRM 的行业模块(报表模板、认证方式、数据导出等)
- 客户定制功能独立分发
- 脚本执行器/工具集的组件化发布
类比:VS Code 扩展市场
如果你的产品需要像 VS Code 那样的插件生态——远程查询扩展、一键安装、版本兼容检查、依赖自动安装、失败回滚——GeneralUpdate.Extension 提供了完整的底层能力。你只需要在此基础上搭一个"扩展市场"的 UI。
1.2 环境与依赖
| 项目 | 说明 |
|---|---|
| 版本 | 10.5.0-beta.2 |
| 目标框架 | netstandard2.0(兼容 .NET Framework 4.6.1+ / .NET Core 2.0+ / .NET 5+) |
| 依赖包 | Microsoft.Extensions.DependencyInjection、Microsoft.Extensions.Logging.Abstractions、Microsoft.Extensions.Options、Newtonsoft.Json、System.Net.Http、System.IO.Compression、System.IO.Compression.ZipFile |
| 兼容性 | 所有支持 .NET Standard 2.0 的平台 |
2. 组件功能列表
| 功能名称 | 功能描述 | 类型 | 是否必填 | 备注限制 |
|---|---|---|---|---|
| 扩展查询 | 从服务端 API 分页查询扩展列表 | 基础 | 推荐 | 支持多条件筛选 |
| 扩展下载 | 从服务端下载扩展 ZIP 包,支持断点续传 | 基础 | 自动 | 通过 DownloadExtensionAsync 或一键更新自动触发 |
| 扩展安装 | 安全解压 ZIP 到本地目录,支持 Zip Slip 防护和回滚 | 基础 | 自动 | 仅接受 .zip 格式 |
| 一键更新 | 自动串起查询→兼容性→依赖→下载→校验→安装全流程 | 基础 | 推荐 | UpdateExtensionAsync |
| 批量更新 | 按顺序批量更新多个扩展 | 拓展 | 可选 | UpdateExtensionsAsync |
| 扩展卸载 | 从本地 catalog 移除并删除扩展目录 | 基础 | 可选 | UninstallExtensionAsync |
| 版本兼容性检查 | 宿主版本必须在扩展的 Min/Max 范围内 | 基础 | 自动 | 更新流程中自动检查 |
| 平台匹配 | 自动识别当前 OS,匹配扩展支持的平台 | 基础 | 自动 | PlatformMatcher 通过 RuntimeInformation 检测 |
| 依赖递归安装 | 发现未安装依赖时递归调用更新 | 基础 | 自动 | 依赖必须能被同一服务端查询和下载 |
| 循环依赖检测 | 拓扑排序时检测依赖环 | 基础 | 自动 | DependencyResolver |
| SHA256 校验 | 下载后校验文件完整性 | 基础 | 自动 | 服务端 Hash 非空时校验 |
| 本地 Catalog 管理 | 每个扩展独立 manifest.json,原子写入 | 基础 | 自动 | 存储在扩展目录下 |
| 自动更新策略 | 全局/单扩展自动更新开关 | 拓展 | 可选 | 仅在内存中保存状态,不自动轮询 |
| 生命周期钩子 | 安装/激活/停用/卸载前后业务逻辑 | 拓展 | 可选 | 实现 IExtensionLifecycleHooks 或继承 DefaultExtensionLifecycleHooks |
| DI Builder | ExtensionHostBuilder 注册并替换所有服务 | 拓展 | 可选 | 支持自定义 IExtensionServiceFactory |
| 下载队列管理 | 并发下载控制(默认 3) | 拓展 | 可选 | DownloadQueueManager |
3. API 配置说明
3.1 配置字段(属性 Props)
ExtensionHostOptions:
| 字段名 | 数据类型 | 默认值 | 是否必填 | 枚举/取值范围 | 说明 |
|---|---|---|---|---|---|
ServerUrl | string | — | 是 | 有效绝对 URL | 扩展服务根地址,客户端调用 {ServerUrl}/Query 和 {ServerUrl}/Download/{extensionId} |
Scheme | string | "" | 可选 | "Bearer" 等 | Authorization 认证方案,为空不设置认证头 |
Token | string | "" | 可选 | — | Authorization token,需和 Scheme 同时非空才生效 |
HostVersion | string | — | 推荐 | SemVer 格式 | 宿主应用版本,用于兼容性判断 |
ExtensionsDirectory | string | — | 是 | 有效目录路径 | 扩展包下载、安装和 .backup 目录所在位置 |
CatalogPath | string | null | 可选 | 有效目录路径 | 本地扩展目录扫描路径,为空时使用 ExtensionsDirectory |
ExtensionMetadata(本地模型):
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
Id | string | — | 是 | 扩展唯一 ID,依赖、查询、更新、卸载都以它为关键标识 |
Name | string | null | 推荐 | 扩展目录名和包名的稳定名称 |
DisplayName | string | null | 可选 | 展示名称 |
Version | string | null | 推荐 | 扩展版本,建议 1.2.3 格式 |
FileSize | long? | null | 可选 | 包大小(字节) |
Format | string | null | 推荐 | 包格式,当前安装要求 .zip |
Hash | string | null | 推荐 | SHA256,非空时更新流程校验下载文件 |
Publisher | string | null | 可选 | 发布者 |
Categories | string | null | 可选 | 逗号分隔分类 |
SupportedPlatforms | TargetPlatform | All | 推荐 | [Flags] 位标志:Windows(1), Linux(2), MacOS(4), All(7) |
MinHostVersion | string | null | 可选 | 最低宿主版本 |
MaxHostVersion | string | null | 可选 | 最高宿主版本 |
Dependencies | string | null | 可选 | 逗号分隔的依赖扩展 ID |
IsPreRelease | bool | false | 可选 | 是否预发布 |
CustomProperties | string | null | 可选 | JSON 字符串形式的自定义属性 |
ExtensionQueryDTO(查询筛选):
| 字段名 | 数据类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
Id | string? | null | 可选 | 按 ID 精确查询 |
Name | string? | null | 可选 | 按名称模糊匹配 |
Publisher | string? | null | 可选 | 按发布者模糊匹配 |
Category | string? | null | 可选 | 按分类筛选 |
Platform | TargetPlatform? | null | 可选 | 按目标平台筛选 |
HostVersion | string? | null | 可选 | 用于服务端兼容性判断 |
IsPreRelease | bool? | null | 可选 | 是否包含预发布 |
Status | bool? | null | 可选 | 按启用状态筛选 |
PageNumber | int | 1 | 可选 | 页码(从 1 开始) |
PageSize | int | 10 | 可选 | 每页大小 |
3.2 实例方法
IExtensionHost:
| 方法名 | 入参明细 | 使用场景 | 注意事项 |
|---|---|---|---|
QueryExtensionsAsync(ExtensionQueryDTO) | query — 查询条件 | 搜索/浏览可用扩展 | 响应数据在 Body.Items 中 |
DownloadExtensionAsync(string, string) | extensionId — 扩展 ID;savePath — 保存路径 | 单独下载扩展包 | 支持 HTTP Range 断点续传 |
UpdateExtensionAsync(string) | extensionId — 扩展 ID | 一键更新单个扩展(推荐入口) | 串起查询→兼容性→依赖→下载→校验→安装全流程 |
InstallExtensionAsync(string, bool) | extensionPath — ZIP 包路径;rollbackOnFailure — 是否失败回滚 | 手动安装本地扩展包 | 仅接受 .zip 格式 |
UpdateExtensionsAsync(IEnumerable<string>, CancellationToken) | extensionIds — 扩展 ID 列表;ct — 取消令牌 | 批量更新 | 按传入顺序逐个处理 |
UninstallExtensionAsync(string, CancellationToken) | extensionId — 扩展 ID;ct — 取消令牌 | 卸载扩展 | 移除 catalog 记录并删除扩展目录 |
ActivateExtensionAsync(string, CancellationToken) | extensionId;ct | 激活扩展 | 调用生命周期钩子 |
DeactivateExtensionAsync(string, CancellationToken) | extensionId;ct | 停用扩展 | 调用生命周期钩子 |
IsExtensionCompatible(ExtensionMetadata) | extension — 扩展元数据 | 检查扩展兼容性 | 基于 HostVersion 与 MinHostVersion/MaxHostVersion 比较 |
SetAutoUpdate(string, bool) | extensionId — 扩展 ID;autoUpdate — 是否自动更新 | 设置单扩展自动更新开关 | 仅内存状态,不自动后台轮询 |
SetGlobalAutoUpdate(bool) | enabled — 是否启用 | 设置全局自动更新默认值 | 仅内存状态 |
GeneralExtensionHost 附加方法:
| 方法名 | 入参明细 | 使用场景 | 注意事项 |
|---|---|---|---|
IsAutoUpdateEnabled(string) | extensionId — 扩展 ID | 查询指定扩展的自动更新开关 | 单扩展设置优先于全局设置 |
ExtensionHostBuilder:
| 方法名 | 入参明细 | 使用场景 | 注意事项 |
|---|---|---|---|
ConfigureOptions(Action<ExtensionHostOptions>) | configure — 配置委托 | 通过 Lambda 配置选项 | — |
WithOptions(ExtensionHostOptions) | options — 选项对象 | 直接设置选项 | — |
ConfigureServices(Action<IServiceCollection>) | configure — DI 注册委托 | 替换或添加服务 | 在 Build() 前调用 |
Build() | 无 | 构建宿主实例 | 自动注册未覆盖的默认服务 |
3.3 回调事件
| 事件名称 | 回调参数 | 触发时机 | 使用说明 |
|---|---|---|---|
ExtensionUpdateStatusChanged | ExtensionUpdateEventArgs — ExtensionId, ExtensionName, Status, Progress(0-100), ErrorMessage | 扩展更新流程各阶段 | Status: Queued→Updating(下载进度)→UpdateSuccessful/UpdateFailed |
ExtensionUpdateStatus 枚举:
| 值 | 说明 |
|---|---|
Queued (0) | 已加入更新队列 |
Updating (1) | 正在下载/更新中 |
UpdateSuccessful (2) | 更新成功 |
UpdateFailed (3) | 更新失败 |