news 2026/9/27 21:31:49

Orchard Core 临时文件存储深入指南:ITempDirectoryProvider 架构、配置与共享卷挂载实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Orchard Core 临时文件存储深入指南:ITempDirectoryProvider 架构、配置与共享卷挂载实战
  • CMS
  • 后端
  • Web框架

【免费下载链接】OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.

项目地址:https://gitcode.com/gh_mirrors/or/OrchardCore
点击查看免费下载

导读

本文围绕 Orchard Core 的ITempDirectoryProvider临时文件存储抽象展开,介绍它在分片上传、TUS 断点续传、部署/Recipe 导入导出等场景中的核心作用,说明如何通过OrchardCore:TempDirectory:Path一项全局配置把临时文件从系统临时目录迁移到更大的共享卷(如 Azure Files、AWS EFS/FSx),并给出面向开发者的 API 使用方式与实现替换方法。读完本文,你将掌握 Orchard Core 临时文件目录的租户隔离机制、配置落地方式,以及如何在自己的功能模块中正确消费这套抽象。

一、为什么需要ITempDirectoryProvider

Orchard Core 在运行中需要写临时文件的场景非常多,例如:

  • 进行中的分片上传(chunked upload)——大文件被切分为多个分片,跨多次请求写入同一个临时文件;
  • 可断点续传的 TUS 上传——部分上传数据在完成前需要持久保存;
  • 部署 / Recipe 导入导出——先落地压缩包,再解压到临时目录处理;
  • 站点 Setup 前写入磁盘的 Recipe 文件。

这些消费者早期直接使用Path.GetTempPath()写系统临时目录。但系统临时目录的空间常常受限:小型系统临时卷、容器化的临时磁盘都容易在小空间下被大量并发大文件上传填满。因此 Orchard Core 引入了ITempDirectoryProvider抽象(位于OrchardCore.FileStorage命名空间),让临时文件的基路径可配置,操作者可以把它指向一个按工作负载规模规划好的卷——包括多实例部署下的共享网络卷,这样在一台实例上开始的断点上传可以由另一台实例继续完成。

源码佐证:抽象只给路径,不碰文件内容

从 ITempDirectoryProvider.cs 可以看到,这个抽象只负责分发真实本地文件系统路径,调用方自己用System.IOAPI 完成实际读写,接口本身不读不写文件内容:

  • GetRootDirectory():返回租户作用域的根目录(按需创建);
  • CreateTempSubdirectory(string prefix = null):在根目录下创建唯一命名的新子目录,可选前缀;
  • GetTempFileName(string extension = null):返回根目录下一个唯一的新文件路径(文件本身不会创建),扩展名可带或不带前导点。

二、默认实现与租户隔离

默认实现DefaultTempDirectoryProvider是基于文件系统的。其构造函数逻辑(见 DefaultTempDirectoryProvider.cs)非常清晰:

var basePath = options.Value.Path; if (string.IsNullOrWhiteSpace(basePath)) { basePath = Path.GetTempPath(); } // Scope temporary files per tenant so that tenants can neither collide with nor observe each other's files. _rootPath = Path.Combine(basePath, shellSettings.Name);

也就是说:

  1. 读取TempDirectoryOptions.Path,未配置时回退到Path.GetTempPath();
  2. 用Path.Combine(basePath, shellSettings.Name)拼出租户隔离的根路径。

目录布局

临时文件一律按{Path}/{TenantName}/...布局。租户子目录由实现自动拼接,操作者永远不需要自己拼。租户隔离的意义在于:不同租户的临时文件互不冲突、互不可见——代码注释明确写道 "tenants can neither collide with nor observe each other's files"。

权限与回退行为

  • 在 Unix-like 系统上,新建的租户目录使用仅属主权限(UnixFileMode.UserRead | UserWrite | UserExecute,即700),与Directory.CreateTempSubdirectory()的行为一致(见 DefaultTempDirectoryProvider.cs);
  • 当Path未设置时,回退到操作系统临时目录,保持旧行为不变。

这些行为都有测试覆盖。在 DefaultTempDirectoryProviderTests.cs 中可以看到:

  • GetRootDirectory_ReturnsTenantScopedPath_AndCreatesIt:验证根路径为{basePath}/{TenantName}且目录被创建;
  • GetRootDirectory_OnUnix_CreatesWithOwnerOnlyPermissions:验证 Unix 下的700权限;
  • DifferentTenants_GetIsolatedRoots:验证不同租户得到隔离的根路径;
  • EmptyTempPath_FallsBackToSystemTempPath:验证未配置时回退到Path.GetTempPath();
  • GetTempFileName_HonorsExtension:验证扩展名无论带不带前导点,最终都规范为.zip这样的带点形式;
  • CreateTempSubdirectory_AppliesPrefixToDirectoryName:验证前缀被拼到生成的目录名前。

三、全局配置:OrchardCore:TempDirectory

基路径由OrchardCore:TempDirectory配置节全局控制,对应 TempDirectoryOptions.cs 中的Path属性。完整配置示例:

{ "OrchardCore": { "TempDirectory": { // Base path under which tenant-scoped temporary files are stored. // When omitted, the operating system temporary directory (Path.GetTempPath()) is used. "Path": "/mnt/shared/temp" } } }

配置如何生效

从注册代码(见 ServiceCollectionExtensions.cs)可以看到两个关键细节:

  1. services.TryAddSingleton<ITempDirectoryProvider, DefaultTempDirectoryProvider>()——它是租户级单例(不是宿主级单例),因为它依赖租户的ShellSettings;
  2. services.Configure<TempDirectoryOptions>(configuration.GetSection("TempDirectory"))——配置节从租户级IShellConfiguration读取TempDirectory段,绑定到选项类。

因此这一项设置会作用于所有临时文件消费者:媒体分片上传、TUS 上传、部署与 Recipe 的导入/导出、租户 Recipe 上传等,全部跟随OrchardCore:TempDirectory:Path。

TUS 断点续传的例外说明

需要注意一个细节:可断点续传的TUS 部分上传数据存放在该位置的TusUploads子目录下。源码佐证见 DiskTusTempStore.cs——它用Path.Combine(tempDirectoryProvider.GetRootDirectory(), "TusUploads")拼出存储目录,因此同样遵循OrchardCore:TempDirectory:Path。

四、挂载共享文件系统(Azure Files、AWS EFS/FSx)

因为DefaultTempDirectoryProvider只使用普通的System.IO操作,任何以已挂载文件系统路径形式呈现的存储都无需改代码即可工作——本地磁盘、SAN/NAS 卷、SMB 共享(Azure Files)、NFS 共享(AWS EFS/FSx)均可。在操作系统层面完成挂载后,把Path设为挂载点即可。

Linux / 容器(SMB 挂载 Azure Files)

sudo mkdir -p /mnt/octemp sudo mount -t cifs //<account>.file.core.windows.net/<share> /mnt/octemp \ -o vers=3.0,username=<account>,password=<storage-key>,dir_mode=0777,file_mode=0777,serverino,nosharesock,actimeo=30
{ "OrchardCore": { "TempDirectory": { "Path": "/mnt/octemp" } } }

Windows

New-SmbGlobalMapping -RemotePath "\\<account>.file.core.windows.net\<share>" -Credential $cred -Persistent $true -LocalPath Z:
{ "OrchardCore": { "TempDirectory": { "Path": "Z:\\octemp" } } }

Azure App Service / Container Apps

使用平台自带的 Azure Files 挂载能力(App Service:Configuration → Path mappings → Azure Storage Mounts;Container Apps:AzureFile卷),然后把Path设为平台挂载路径(如/mounts/octemp)。凭据与重连都由平台托管。

重要警告:必须是文件共享,不能是对象存储

把Path指向挂载的文件共享,而不是对象存储。临时文件消费者要求真实、可随机访问的本地文件:

  • 分片上传路径会执行Seek/SetLength,并跨请求重新打开同一个文件(参见 ChunkFileUploadService.cs 中对FileStream.Seek(contentRange.From, SeekOrigin.Begin)的使用);
  • 部署导入会使用ZipFile.ExtractToDirectory和PhysicalFileProvider。

Azure Files(SMB)和 AWS EFS/FSx 支持这种语义;Azure Blob 和 AWS S3 对象存储不支持。唯一的例外是 TUS 断点续传:它可以通过OrchardCore.Media.Azure与OrchardCore.Media.AmazonS3功能中的ITusTempStore实现直接以对象存储为目标(仓库中可找到 AzureBlobTusTempStore.cs 等实现)。

运维注意事项

  • 确保挂载点对应用运行身份可写;
  • 共享卷与实例保持在同一区域,以降低延迟;
  • 现有清理任务(如媒体模块的TemporaryFileLifetime过期清理)现在会作用于配置后的路径——例如 ChunkFileUploadService.cs 中的PurgeTempDirectory()会按TemporaryFileLifetime清理超龄临时文件。

五、在功能模块中消费ITempDirectoryProvider

如果你的功能需要写临时文件,请注入ITempDirectoryProvider,而不是直接调用Path.GetTempPath()。这样你的临时文件会自动落入配置好的、租户隔离的位置。

API 速查表

成员用途
GetRootDirectory()租户作用域根目录(按需创建)。作为需要目录的工具的基础,例如TemporaryFileBuilder。
GetTempFileName(extension)唯一的文件路径(不会创建文件),用于写单个临时文件。扩展名可选,带或不带前导点均可。
CreateTempSubdirectory(prefix)新建的唯一子目录——用于解压归档,或通过PhysicalFileProvider暴露。可选前缀会拼到生成名称前。

完整示例:导入服务

using OrchardCore.FileStorage; public sealed class MyImportService { private readonly ITempDirectoryProvider _tempDirectoryProvider; public MyImportService(ITempDirectoryProvider tempDirectoryProvider) => _tempDirectoryProvider = tempDirectoryProvider; public async Task ImportAsync(IFormFile package, CancellationToken cancellationToken) { // A unique file path under {Path}/{TenantName}/ to save the upload. var archivePath = _tempDirectoryProvider.GetTempFileName(Path.GetExtension(package.FileName)); // A dedicated directory to extract into. var extractPath = _tempDirectoryProvider.CreateTempSubdirectory(); try { await using (var stream = File.Create(archivePath)) { await package.CopyToAsync(stream, cancellationToken); } ZipFile.ExtractToDirectory(archivePath, extractPath); // ... process the extracted files ... } finally { File.Delete(archivePath); Directory.Delete(extractPath, recursive: true); } } }

记住两点

  1. 只管路径,清理自理:store 只负责给出路径,文件的创建、写入和清理完全由调用方负责。用完即删,store 不会替你跟踪或过期清理。
  2. 临时 ≠ 安全:ITempDirectoryProvider只提供临时存储,它不扫描上传内容。当临时文件来自用户上传时,在永久落盘之前仍应经过FileCreationService的安全检查(详见上传安全文档 file-upload-security.md)。

六、替换默认实现

DefaultTempDirectoryProvider以TryAddSingleton方式按租户注册(见 ServiceCollectionExtensions.cs),因此模块可以用自己的实现替换:

services.Replace(ServiceDescriptor.Singleton<ITempDirectoryProvider, MyTempDirectoryProvider>());

任何替代实现都必须遵守同一契约:返回真实本地文件系统路径,支持随机访问与目录枚举。这正是仓库中没有 Azure Blob 或 AWS S3 版ITempDirectoryProvider的原因——对象存储无法满足消费者依赖的“基于路径、可随机访问”的契约。要把临时存储搬到云上,正确做法是挂载文件共享(Azure Files、AWS EFS/FSx)并配置Path,即本文第四节所述方案。

七、小结与检查清单

ITempDirectoryProvider是 Orchard Core 统一管理临时文件的入口:一份OrchardCore:TempDirectory:Path配置,即可把分片上传、TUS 上传、部署/Recipe 导入导出等全部临时文件消费者迁移到大容量或共享卷,同时天然获得按租户的目录隔离。落地时请对照以下清单:

  • 在生产环境显式配置OrchardCore:TempDirectory:Path,避免依赖空间受限的系统临时目录;
  • 多实例部署时优先使用共享文件系统(Azure Files / AWS EFS/FSx),实现跨实例断点续传;
  • 确认挂载点对应用运行身份可写、与实例同区域;
  • 确认消费者要求的Seek/SetLength、ZipFile.ExtractToDirectory、PhysicalFileProvider语义得到满足(文件共享可以,对象存储不行);
  • 自研功能一律注入ITempDirectoryProvider,不要直接调Path.GetTempPath();
  • 用完删除临时文件,上传文件在落盘前仍要走FileCreationService安全检查。

参考文件速览

  • 本文原始依据:temporary-file-storage.md
  • 抽象接口:ITempDirectoryProvider.cs
  • 默认实现:DefaultTempDirectoryProvider.cs
  • 配置选项:TempDirectoryOptions.cs
  • 注册与绑定:ServiceCollectionExtensions.cs
  • 分片上传消费者:ChunkFileUploadService.cs
  • TUS 磁盘存储:DiskTusTempStore.cs
  • 单元测试:DefaultTempDirectoryProviderTests.cs
  • 上传安全检查:file-upload-security.md
  • CMS
  • 后端
  • Web框架

【免费下载链接】OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.

项目地址:https://gitcode.com/gh_mirrors/or/OrchardCore
点击查看免费下载

相关推荐

上一篇:音乐下载神器:MusicDownload 让你的音乐收藏更简单
下一篇:DDT4All汽车诊断工具:从入门到精通的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 21:21:51

多个AI Agent同时预订同一家酒店,谁更可靠

我的信用卡这个月被划走了四笔订阅费&#xff0c;全部是AI开发工具。这不是最离谱的&#xff0c;最离谱的是其中两个的功能我到现在也没分清&#xff0c;每次打开都像在见一对双胞胎。 事情要从两个月前说起。我想做一个能自动查酒店价格、降价就提醒我的Agent&#xff0c;需求…

作者头像 李华