跳到主要内容

文件与通用附件

文件能力位于 FreeKit.Identity.Infrastructure,由两套相关但不同的模型组成:

  • KitFile 记录一次文件上传及其存储位置,主键是 long
  • CommonAttachment 记录某个业务实体使用的附件快照,主键是 Guid

CommonAttachment 当前没有 KitFileId 外键。上传后创建附件时,需要把 FileDto 的名称、路径和大小复制到附件输入;不要把它描述成一张只保存文件 Id 的关联表。

KitFile

实体路径:src/Services/Identity/FreeKit.Identity.Infrastructure/Domain/Files/KitFile.cs

public class KitFile : FullAuditEntity<long, long>, ITenant
字段类型含义
Idlong文件记录主键
TenantIdGuid?租户
FileMetaIdlong?可选 KitFileMeta 主键
Extensionstring扩展名
Hashstring文件哈希,用于去重
Namestring文件名称
Hoststring?存储域名
Pathstring存储相对路径/对象 Key
Sizelong?文件字节数
TypeFileUploadType?Local、Qiniu、CloudFlare 等存储类型
IsFileExistbool后端文件是否仍存在

KitFileMeta 也是 long 主键,只包含 HashName;它不是任意 Key/Value 元数据表。

API 返回的 FileDto 包含:

public class FileDto : EntityDto<long>
{
public string Key { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string Url { get; set; }
public long Size { get; set; }
public FileUploadType Type { get; set; }
}

CommonAttachment

实体路径:src/Services/Identity/FreeKit.Identity.Infrastructure/Domain/CommonAttachments/CommonAttachment.cs

public class CommonAttachment : FullAuditEntity, ITenant
字段类型含义
IdGuid附件记录主键
EntityIdGuid业务实体主键
EntityTypestring已注册的业务实体类型,例如 Article
Categorystring?业务分类,例如 Article/Content
FileNamestring文件名快照
FilePathstring文件路径快照
FileSizelong文件大小快照
AttachmentTypeAttachmentTypeImage、Video、Audio、Document、Other
FileMetaIdint?历史元数据标识;当前没有到 KitFileMeta(long) 的导航或外键
Sortint升序展示顺序
AltTextstring图片描述/Alt 文本
IsFileExistbool文件存在状态

列表 DTO 会根据 FilePath 通过 IFileManager.GetFileUrlAsync 补充 FileUrl

文件 API

Controller:FreeKit.Identity.Infrastructure.Application.Files.FileController

基础路由:/api/identity/file,继承 FreeKitController,默认要求登录。

方法路由额外权限用途
POST/uploads登录files 表单字段,多文件上传
POST/upload登录file 表单字段,单文件上传
POST/upload-from-url?url=...登录从 URL 拉取并保存
GET/{id:long}登录获取文件信息和可访问 URL
GET/Identity.Files.GetList分页查询文件
PUT/{id:long}Identity.Files.GetList修改文件名称
DELETE/{id}Identity.Files.GetList通过审计仓储软删除文件记录
PUT/check_all_file_existsIdentity.Files.GetList批量刷新本地文件存在状态
GET/check_file_exists/{id:long}Identity.Files.GetList检查单个文件

三个头像辅助接口 create_avatarcreate_avatar_url_by_nameget_random_avatar 当前标记为匿名。

请求经过 MultipartRequestHelper 检查 Content-Type。多文件上传还会检查 NumLimit、总大小和扩展名;单文件同样执行扩展名白名单/黑名单检查。

通用附件 API

Controller:FreeKit.Identity.Infrastructure.Application.CommonAttachments.CommonAttachmentController

基础路由:/api/identity/common-attachment

方法路由认证用途
POST/登录创建一个附件快照
DELETE/{id:guid}登录删除附件;非 Admin 只能删除自己的记录
GET/?entityId=...&entityType=...匿名分页查询附件
GET/{entityId:guid}登录查询某实体的全部附件
PUT/check_all_file_exists登录刷新本地附件存在状态

匿名列表至少需要 EntityIdEntityIdsEntityType 之一,否则 Manager 返回空结果。查询还支持 CategoryAttachmentType

批量新增/更新、按实体删除和云端同步存在于 ICommonAttachmentService,但当前没有由这个 Controller 直接公开成 REST Action;它们由文章、沸点、举报等业务服务内部调用。

上传后创建附件

下面代码使用真实的 FileDtoAttachmentCreateInput 字段:

FileDto file = await fileService.UploadAsync(formFile);

await attachmentService.AddAttachmentAsync(new AttachmentCreateInput
{
EntityId = articleId,
EntityType = "Article",
Category = "Article/Content",
AttachmentType = AttachmentType.Image,
FileName = file.Name,
FilePath = file.Path,
FileSize = file.Size
});

CmsKit 在 CmsKitModuleStartup.Subdomains.cs 注册了当前允许的组合:

  • Article/Cover:Image
  • Article/Content:Image、Video、Audio、Document、Other
  • ShortMsg/Media:Image、Video、Audio
  • UserReport/Evidence:Image

CommonAttachmentValidatorBase 会先确认 EntityType 已注册,再检查分类和附件类型;配置了 IEntityAccessValidator 时还会验证当前用户能否访问目标实体。

如果 AttachmentType 使用默认值,CommonAttachmentService 当前会按扩展名推断类型用于规则校验,但不会把推断值回写到传给 Manager 的输入。因此调用方应显式提交 AttachmentType;否则记录可能保存枚举默认值 0。这是当前实现需要后续修正的边界,文档示例不依赖隐式推断。

存储配置

IdentityInfrastructureModuleStartup 绑定 FileStorage,并注册当前确实存在的三个 keyed uploader:

  • LocalFileManager
  • QiniuManager
  • CloudFlareR2

安全的本地开发示例:

{
"FileStorage": {
"MaxFileSize": 1073741824,
"NumLimit": 3,
"Include": "",
"Exclude": ".exe,.dll,.jar",
"ServiceName": "LocalFileManager",
"ImgExtensions": "jpg,jpeg,png,gif,webp",
"LocalFile": {
"RootPath": "",
"PrefixPath": "assets",
"Host": "https://api.example.com/kit_api/"
}
}
}

ServiceName 必须与注册 key 完全一致。Cloudflare R2 和七牛配置中的访问凭据必须通过环境变量、Secret Manager 或用户机密提供,不要写进文档或提交到仓库。

IdentityInfrastructureModuleStartup 将 multipart body 上限设为 1 GiB、单个普通表单值上限设为 8 MiB;文件服务自己的 MaxFileSizeNumLimit 仍需按业务场景配置,不能只依赖 Kestrel/Form 上限。

结构同步

IdentityInfrastructureModuleStartup.ConfigureDEBUG 下同步:

  • KitFileMeta
  • KitFile
  • CommonAttachment

Release 启动不会依靠这段 SyncStructure 建表,部署文档应要求显式迁移或提前初始化数据库。

源码索引

  • src/Services/Identity/FreeKit.Identity.Infrastructure/Application/Files/FileController.cs
  • src/Services/Identity/FreeKit.Identity.Infrastructure/Application/Files/FileService.cs
  • src/Services/Identity/FreeKit.Identity.Infrastructure/Application/CommonAttachments/CommonAttachmentController.cs
  • src/Services/Identity/FreeKit.Identity.Infrastructure/Application/CommonAttachments/CommonAttachmentService.cs
  • src/Services/Identity/FreeKit.Identity.Infrastructure/Domain/CommonAttachments/CommonAttachmentManager.cs
  • src/Services/Identity/FreeKit.Identity.Infrastructure/IdentityInfrastructureModuleStartup.cs

相关文档