跳到主要内容
版本:3.1

本地文件存储(Aegis.FileManager.Local)

Local 是 Aegis.FileManager 基础包内置的本地文件系统存储实现,把文件读写落到进程可直写的磁盘目录。纯 System.IO 实现,零网络依赖,不计算 MD5。

StorageKey(文件路径)的拼装规则属于业务领域,详见 文件管理 — 核心概念:业务自拼 Key。本页只讲 Local 后端的接入与配置。

组件概览​

字段说明
组件名称本地文件存储
真实类库Aegis.FileManager(基础包内置 Local Provider,无独立 NuGet 包)
最新版本3.1.4-preview4
组件定位本地文件系统存储实现,轻量默认 Provider
引入方式引用基础包即具备;Component.deps.json 声明 LocalFileManager + 配置 LocalStorage 节启用
核心能力IFileManager 实现、IFileStorage 目录管理、零网络依赖、不算 MD5
主要配置LocalStorage
典型配套文件管理基础层(Aegis.FileManager)、诊断组件(Aegis.Diagnostics)

什么时候要用它​

适合场景:

  • 单机部署,文件直接写本地磁盘就够
  • 容器部署,写 Pod 本地盘或挂载卷(emptyDir / hostPath / PVC 皆可)
  • 开发、测试环境需要一个零依赖的文件存储,不搭 MinIO 也不挂 NAS
  • 不需要文件 MD5,ContentMd5 为空可接受

不适合场景:

  • 多节点部署需要共享文件(用 S3 对象存储,或各节点挂载同一 NAS 用 NAS 本地存储)
  • 需要客户端直连下载 URL(Local 的 GetFileUriAsync 返回的是服务器本地路径,浏览器拿不到)

显式 Provider,不是隐式兜底​

Local 不会在「什么都没配」时自动生效。启用它必须同时满足两个条件:

  1. Component.deps.json 的 Load 列表声明 LocalFileManager
  2. appsettings.json 配置 LocalStorage 节(RootPath 必填)

两项缺一,Local 都不注册,应用行为与未引入时完全一致。声明了组件但没配节,启动横幅会直接报 Failure(见下方缺节行为),不会静默跳过。

最小可运行路径​

第一步:确认引用​

Local 内置在基础包里,项目引用 Aegis.FileManager 即可(Aegis.FileManager.Nas / .S3 / .WebDav 等实现包都传递引用它,装了任一实现包也具备 Local 能力)。

dotnet add package Aegis.FileManager

第二步:准备配置​

appsettings.json 添加 LocalStorage 节:

{
"LocalStorage": {
"RootPath": "/data/aegis-files"
}
}

第三步:在 Component.deps.json 中声明​

{
"Components": {
"Load": [
"LocalFileManager"
]
}
}

Load 列表里还有其他组件时,把 LocalFileManager 加进同一数组即可。启动横幅出现「已注入服务 LocalFileManager」即注册成功。

也可以走 Startup 手动注册(两条路径二选一,不要同时用):

using Aegis.FileManager;

services.AddLocalFileManager(new LocalOptions { RootPath = "/data/aegis-files" });

第四步:在业务里使用​

public class AttachmentService
{
private readonly IFileManager _fileManager;

public AttachmentService(IFileManager fileManager) => _fileManager = fileManager;

public Task<FileUploadResult> Upload(string fileName, Stream stream, string group = "")
=> _fileManager.UploadFileAsync(fileName, stream, group);

public Task<string> GetUri(string fileName, string group = "")
=> _fileManager.GetFileUriAsync(fileName, group);
}

完整的业务自拼 Key 模式与 EMR 病历示例,见 文件管理 — 核心概念:业务自拼 Key。

配置项说明(LocalOptions)​

配置项类型默认值说明
RootPathstring""必填,无默认值。存储根目录,所有文件操作都基于此路径。相对路径按进程工作目录解析,生产环境建议显式配置绝对路径

和 NasStorage:RootPath 的差异:NAS 的 RootPath 有默认值 "/rootPath",Local 刻意去掉了默认值。RootPath 为空时 deps 路径与手动路径都会报错,逼着部署者显式指定落盘位置,避免文件散落在意外的工作目录里。

行为细则​

行为说明
ContentMd5不计算,GetFileInfoAsync 返回的 ContentMd5 为空。要 MD5 的场景用 NAS 后端(EnableMd5Calculation)或业务侧自行计算
groupName 含义RootPath 下的子目录,与 NAS 一致
GetFileUriAsync返回文件在本机的绝对路径(/ 分隔),不是可访问 URL
DeleteFileAsync幂等,文件不存在返回 true(与 NAS / S3 / WebDAV 对齐)
ListFilesAsync仅直接子文件(非递归),prefix 客户端过滤,continuationToken 为上一页最后一个文件名,与 NAS 同一套分页语义
GetFileAsyncfilePath 目录 / 完整路径两种传法自动识别,规则见 文件管理 — GetFileAsync 的 filePath 参数约定
路径遍历防护LocalPathHelper.MapToLocalPath 与 NasPathHelper 同款防护:GetFullPath 解析后做带边界分隔符的根范围校验,逃逸出 RootPath 的路径抛 ArgumentException

缺节行为​

deps.json 声明了 LocalFileManager 但 appsettings 没有对应的 LocalStorage 节时,注册返回显式 Failure,启动横幅直接可见:

注入服务失败 LocalFileManager
Fail: Component.deps.json 已声明 LocalFileManager,但未找到 LocalStorage 配置节;请补齐 appsettings 配置或从 Load 列表移除该组件

处理方式横幅里已经写明:要么补配置节,要么从 Load 列表移除组件。

与其他后端共存:单注入守卫​

IFileManager 在一个进程里只能有一个默认实现。已经注册过 IFileManager 时,第二个 AddXxxFileManager(Local / Nas / S3 / WebDAV 任一组合)抛 InvalidOperationException:

  • deps.json 路径的冲突表现为横幅 Failure,先声明的组件生效
  • Startup 手动路径的冲突直接中止启动

升级到 3.1.4-preview4 后若启动报「IFileManager 已注册」,检查 Startup 里是否残留了旧的手动注册行,删掉即可。详见 文件管理 — 单注入守卫。

诊断三件套​

需要装配 诊断组件(Aegis.Diagnostics)(deps.json 声明 Diagnostics)。未装配时三件套是无人消费的惰性单例,零开销。

诊断能力内容
健康探针探针名「文件存储 · Local」。RootPath 下写 → 读 → 删探针文件 .aegis-healthprobe,5 秒超时;根目录缺失时自动创建并在结果里标注「根路径原不存在(已自动创建,请确认 RootPath 拼写)」。BlocksReady = true:存储不可用即摘流量。启动即巡检(dueTime 0)并周期复巡
诊断段/diag 页面「文件存储 · Local」段:类型、根路径
网络分层诊断/diag 段头「一键诊断 ›」触发(端点 ?diagnose=),Local 走路径三步:根路径存在性 → 可写探测(写删探针文件)→ 磁盘容量(总容量 / 可用容量)

接入后怎么确认生效​

按下面几项验收:

  • 启动横幅「检查遗漏服务」不再出现「当前未加载 LocalFileManager」
  • IFileManager 可以正常注入
  • UploadFileAsync 后,LocalStorage:RootPath 下能看到对应分组目录与文件
  • GetFileBytesAsync / DeleteFileAsync 正常工作,删除后再 DoesFileExistAsync 返回 false
  • 装配了 Diagnostics 时,/diag 页面出现「文件存储 · Local」段,健康矩阵里该探针为绿

常见问题​

Local 和 NAS 都是本地盘读写,怎么选​

两者实现路线一样(System.IO 直写),差别在定位:

差异点LocalNAS
所在包基础包内置,无额外引用独立包 Aegis.FileManager.Nas
MD5不算,ContentMd5 为空EnableMd5Calculation 控制,默认算
RootPath 默认值无默认,必填默认 "/rootPath"
典型场景开发调试、单机、容器本地卷生产挂载 NAS / 共享目录,需要 MD5

单机轻量用 Local;生产环境要 MD5、或有共享挂载诉求,用 NAS。

没配 RootPath 会怎样​

  • deps.json 路径:LocalStorage 节缺失 → 启动横幅 Failure(节存在但 RootPath 为空同样过不了校验,AddLocalFileManager 抛 ArgumentException,deps 路径转为横幅 Failure)
  • 手动路径:AddLocalFileManager 直接抛 ArgumentException(LocalStorage:RootPath 不能为空)

启动横幅出现「当前未加载 LocalFileManager」是什么意思​

「检查遗漏服务」段列出的是「程序集已引用、但没写进 Load 列表」的组件。业务确实用文件存储时,这条提示等于漏配:把 LocalFileManager(或你实际要用的后端)加进 deps.json,并补上对应配置节。判读细节见 文件管理 — 启动横幅判读指引。

配套阅读​