ASP.NET Core 中的文件提供程序File Providers in ASP.NET Core

本文内容

作者:Steve Smith

ASP.NET Core 通过文件提供程序来抽象化文件系统访问。在 ASP.NET Core 框架中使用文件提供程序:

  • IWebHostEnvironment 将应用的内容根目录Web 根目录作为 IFileProvider 类型公开。
  • 静态文件中间件使用文件提供程序来查找静态文件。
  • Razor 使用文件提供程序来查找页面和视图。
  • .NET Core 工具使用文件提供程序和 glob 模式来指定应该发布哪些文件。

查看或下载示例代码如何下载

文件提供程序接口File Provider interfaces

主接口为 IFileProviderIFileProvider 公开方法以实现以下目的:

IFileInfo 提供用于处理文件的方法和属性:

可以使用 IFileInfo.CreateReadStream 方法从文件读取内容。

示例应用演示了如何在 Startup.ConfigureServices 中配置文件提供程序,以便通过依赖关系注入在应用中使用。

文件提供程序实现File Provider implementations

IFileProvider 有三种实现。

实现描述
PhysicalFileProvider物理提供程序用于访问系统的物理文件。
ManifestEmbeddedFileProvider清单嵌入式提供程序用于访问程序集中嵌入的文件。
CompositeFileProvider复合式提供程序提供对一个或多个其他提供程序中的文件和目录的合并访问。

PhysicalFileProviderPhysicalFileProvider

PhysicalFileProvider 提供对物理文件系统的访问。PhysicalFileProvider 使用 System.IO.File 类型(适用于物理提供程序)并将所有路径范围限定在一个目录及其子目录中。此范围界定可防止访问指定目录和子目录之外的文件系统。创建和使用 PhysicalFileProvider 的最常见方案是通过依赖关系注入请求构造函数中的 IFileProvider

直接实例化此提供程序时,必须提供目录路径并将其作为使用提供程序发出的所有请求的基路径。

下面的代码演示如何创建 PhysicalFileProvider 并用它来获取目录内容和文件信息:

  1. var provider = new PhysicalFileProvider(applicationRoot);
  2. var contents = provider.GetDirectoryContents(string.Empty);
  3. var fileInfo = provider.GetFileInfo("wwwroot/js/site.js");

前面的示例中的类型:

  • providerIFileProvider
  • contentsIDirectoryContents
  • fileInfoIFileInfo

文件提供程序可用于循环访问 applicationRoot 指定的目录或调用 GetFileInfo 来获取文件信息。该文件提供程序无法访问 applicationRoot 目录外部的任何内容。

示例应用使用 IHostingEnvironment.ContentRootFileProvider 在应用的 Startup.ConfigureServices 类中创建提供程序:

  1. var physicalProvider = _env.ContentRootFileProvider;

ManifestEmbeddedFileProviderManifestEmbeddedFileProvider

ManifestEmbeddedFileProvider 用于访问嵌入在程序集中的文件。ManifestEmbeddedFileProvider 使用编译到程序集中的某个清单来重建嵌入的文件的原始路径。

将包引用添加到 Microsoft.Extensions.FileProviders.Embedded 包的项目。

若要生成嵌入的文件清单,请将 <GenerateEmbeddedFilesManifest> 属性设置为 true指定要使用 <EmbeddedResource> 嵌入的文件:

  1. <Project Sdk="Microsoft.NET.Sdk.Web">
  2. <PropertyGroup>
  3. <TargetFramework>netcoreapp3.1</TargetFramework>
  4. <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  5. </PropertyGroup>
  6. <ItemGroup>
  7. <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" />
  8. </ItemGroup>
  9. <ItemGroup>
  10. <EmbeddedResource Include="Resource.txt" />
  11. </ItemGroup>
  12. </Project>

使用 glob 模式指定要嵌入到程序集中的一个或多个文件。

示例应用创建 ManifestEmbeddedFileProvider 并将当前正在执行的程序集传递给其构造函数。

Startup.cs

  1. var manifestEmbeddedProvider =
  2. new ManifestEmbeddedFileProvider(typeof(Program).Assembly);

其他重载使你能够:

  • 指定相对文件路径。
  • 将文件范围限制到上次修改日期。
  • 为包含嵌入文件清单的嵌入资源命名。
重载描述
ManifestEmbeddedFileProvider(Assembly, String)接受一个可选的 root 相对路径参数。指定 root 将对 GetDirectoryContents 的调用范围限制为提供的路径下的那些资源。
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset)接受一个可选的 root 相对路径参数和一个 lastModified 日期 (DateTimeOffset) 参数。lastModified 日期限制 IFileProvider 返回的 IFileInfo 实例的上次修改日期范围。
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset)接受一个可选的 root 相对路径、lastModified 日期和 manifestName 参数。manifestName 表示包含清单的嵌入资源的名称。

CompositeFileProviderCompositeFileProvider

CompositeFileProvider 合并 IFileProvider 实例,以便公开一个接口来处理多个提供程序中的文件。创建 CompositeFileProvider 时,将一个或多个 IFileProvider 实例传递给其构造函数。

在示例应用中,PhysicalFileProviderManifestEmbeddedFileProvider 向在应用的服务容器中注册的 CompositeFileProvider 提供文件:

  1. var physicalProvider = _env.ContentRootFileProvider;
  2. var manifestEmbeddedProvider =
  3. new ManifestEmbeddedFileProvider(typeof(Program).Assembly);
  4. var compositeProvider =
  5. new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);
  6. services.AddSingleton<IFileProvider>(compositeProvider);

监视更改Watch for changes

IFileProvider.Watch 方法提供了一个方案来监视一个或多个文件或目录是否发生更改。Watch 接受路径字符串,它可以使用 glob 模式指定多个文件。Watch 返回 IChangeToken更改令牌会公开以下内容:

  • HasChanged – 可检查此属性以确定是否已发生更改。
  • RegisterChangeCallback – 检测到指定的路径字符串发生更改时调用此属性。每个更改令牌仅调用其关联的回调来响应单个更改。若要启用持续监视,请使用 TaskCompletionSource(如下所示)或重新创建 IChangeToken 实例以响应更改。

    在示例应用中,WatchConsole 控制台应用配置为每次修改了文本文件时显示一条消息:
  1. private static PhysicalFileProvider _fileProvider =
  2. new PhysicalFileProvider(Directory.GetCurrentDirectory());
  3. public static void Main(string[] args)
  4. {
  5. Console.WriteLine("Monitoring quotes.txt for changes (Ctrl-c to quit)...");
  6. while (true)
  7. {
  8. MainAsync().GetAwaiter().GetResult();
  9. }
  10. }
  11. private static async Task MainAsync()
  12. {
  13. IChangeToken token = _fileProvider.Watch("quotes.txt");
  14. var tcs = new TaskCompletionSource<object>();
  15. token.RegisterChangeCallback(state =>
  16. ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);
  17. await tcs.Task.ConfigureAwait(false);
  18. Console.WriteLine("quotes.txt changed");
  19. }

某些文件系统(例如 Docker 容器和网络共享)可能无法可靠地发送更改通知。DOTNET_USE_POLLING_FILE_WATCHER 环境变量设置为 1true 以每隔四秒轮询一次文件系统,确认是否发生更改(不可配置)。

glob 模式Glob patterns

文件系统路径使用名为 glob(或通配)模式 的通配符模式。使用这些模式指定文件的组。两个通配符分别是 *

*匹配当前文件夹级别的任何内容、任何文件名或任何文件扩展名。匹配由文件路径中的 /. 字符终止。

**匹配多个目录级别的任何内容。可用于以递归方式匹配目录层次结构中的许多文件。

glob 模式示例

directory/file.txt匹配特定目录中的特定文件。

directory/*.txt匹配特定目录中带 .txt 扩展名的所有文件。

directory/*/appsettings.json匹配正好位于“目录” 文件夹中下一级目录中的所有 appsettings.json 文件。

directory//.txt*匹配在“目录” 文件夹下任何位置找到的带 .txt 扩展名的所有文件。

ASP.NET Core 通过文件提供程序来抽象化文件系统访问。在 ASP.NET Core 框架中使用文件提供程序:

查看或下载示例代码如何下载

文件提供程序接口File Provider interfaces

主接口为 IFileProviderIFileProvider 公开方法以实现以下目的:

IFileInfo 提供用于处理文件的方法和属性:

可以使用 IFileInfo.CreateReadStream 方法从文件读取内容。

示例应用演示了如何在 Startup.ConfigureServices 中配置文件提供程序,以便通过依赖关系注入在应用中使用。

文件提供程序实现File Provider implementations

IFileProvider 有三种实现。

实现描述
PhysicalFileProvider物理提供程序用于访问系统的物理文件。
ManifestEmbeddedFileProvider清单嵌入式提供程序用于访问程序集中嵌入的文件。
CompositeFileProvider复合式提供程序提供对一个或多个其他提供程序中的文件和目录的合并访问。

PhysicalFileProviderPhysicalFileProvider

PhysicalFileProvider 提供对物理文件系统的访问。PhysicalFileProvider 使用 System.IO.File 类型(适用于物理提供程序)并将所有路径范围限定在一个目录及其子目录中。此范围界定可防止访问指定目录和子目录之外的文件系统。创建和使用 PhysicalFileProvider 的最常见方案是通过依赖关系注入请求构造函数中的 IFileProvider

直接实例化此提供程序时,必须提供目录路径并将其作为使用提供程序发出的所有请求的基路径。

下面的代码演示如何创建 PhysicalFileProvider 并用它来获取目录内容和文件信息:

  1. var provider = new PhysicalFileProvider(applicationRoot);
  2. var contents = provider.GetDirectoryContents(string.Empty);
  3. var fileInfo = provider.GetFileInfo("wwwroot/js/site.js");

前面的示例中的类型:

  • providerIFileProvider
  • contentsIDirectoryContents
  • fileInfoIFileInfo

文件提供程序可用于循环访问 applicationRoot 指定的目录或调用 GetFileInfo 来获取文件信息。该文件提供程序无法访问 applicationRoot 目录外部的任何内容。

示例应用使用 IHostingEnvironment.ContentRootFileProvider 在应用的 Startup.ConfigureServices 类中创建提供程序:

  1. var physicalProvider = _env.ContentRootFileProvider;

ManifestEmbeddedFileProviderManifestEmbeddedFileProvider

ManifestEmbeddedFileProvider 用于访问嵌入在程序集中的文件。ManifestEmbeddedFileProvider 使用编译到程序集中的某个清单来重建嵌入的文件的原始路径。

若要生成嵌入的文件清单,请将 <GenerateEmbeddedFilesManifest> 属性设置为 true指定要使用 <EmbeddedResource> 嵌入的文件:

  1. <Project Sdk="Microsoft.NET.Sdk.Web">
  2. <PropertyGroup>
  3. <TargetFramework>netcoreapp2.2</TargetFramework>
  4. <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  5. <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  6. </PropertyGroup>
  7. <ItemGroup>
  8. <PackageReference Include="Microsoft.AspNetCore.App" />
  9. </ItemGroup>
  10. <ItemGroup>
  11. <EmbeddedResource Include="Resource.txt" />
  12. </ItemGroup>
  13. </Project>

使用 glob 模式指定要嵌入到程序集中的一个或多个文件。

示例应用创建 ManifestEmbeddedFileProvider 并将当前正在执行的程序集传递给其构造函数。

Startup.cs

  1. var manifestEmbeddedProvider =
  2. new ManifestEmbeddedFileProvider(typeof(Program).Assembly);

其他重载使你能够:

  • 指定相对文件路径。
  • 将文件范围限制到上次修改日期。
  • 为包含嵌入文件清单的嵌入资源命名。
重载描述
ManifestEmbeddedFileProvider(Assembly, String)接受一个可选的 root 相对路径参数。指定 root 将对 GetDirectoryContents 的调用范围限制为提供的路径下的那些资源。
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset)接受一个可选的 root 相对路径参数和一个 lastModified 日期 (DateTimeOffset) 参数。lastModified 日期限制 IFileProvider 返回的 IFileInfo 实例的上次修改日期范围。
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset)接受一个可选的 root 相对路径、lastModified 日期和 manifestName 参数。manifestName 表示包含清单的嵌入资源的名称。

CompositeFileProviderCompositeFileProvider

CompositeFileProvider 合并 IFileProvider 实例,以便公开一个接口来处理多个提供程序中的文件。创建 CompositeFileProvider 时,将一个或多个 IFileProvider 实例传递给其构造函数。

在示例应用中,PhysicalFileProviderManifestEmbeddedFileProvider 向在应用的服务容器中注册的 CompositeFileProvider 提供文件:

  1. var physicalProvider = _env.ContentRootFileProvider;
  2. var manifestEmbeddedProvider =
  3. new ManifestEmbeddedFileProvider(typeof(Program).Assembly);
  4. var compositeProvider =
  5. new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);
  6. services.AddSingleton<IFileProvider>(compositeProvider);

监视更改Watch for changes

IFileProvider.Watch 方法提供了一个方案来监视一个或多个文件或目录是否发生更改。Watch 接受路径字符串,它可以使用 glob 模式指定多个文件。Watch 返回 IChangeToken更改令牌会公开以下内容:

  • HasChanged – 可检查此属性以确定是否已发生更改。
  • RegisterChangeCallback – 检测到指定的路径字符串发生更改时调用此属性。每个更改令牌仅调用其关联的回调来响应单个更改。若要启用持续监视,请使用 TaskCompletionSource(如下所示)或重新创建 IChangeToken 实例以响应更改。

    在示例应用中,WatchConsole 控制台应用配置为每次修改了文本文件时显示一条消息:
  1. private static PhysicalFileProvider _fileProvider =
  2. new PhysicalFileProvider(Directory.GetCurrentDirectory());
  3. public static void Main(string[] args)
  4. {
  5. Console.WriteLine("Monitoring quotes.txt for changes (Ctrl-c to quit)...");
  6. while (true)
  7. {
  8. MainAsync().GetAwaiter().GetResult();
  9. }
  10. }
  11. private static async Task MainAsync()
  12. {
  13. IChangeToken token = _fileProvider.Watch("quotes.txt");
  14. var tcs = new TaskCompletionSource<object>();
  15. token.RegisterChangeCallback(state =>
  16. ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);
  17. await tcs.Task.ConfigureAwait(false);
  18. Console.WriteLine("quotes.txt changed");
  19. }

某些文件系统(例如 Docker 容器和网络共享)可能无法可靠地发送更改通知。DOTNET_USE_POLLING_FILE_WATCHER 环境变量设置为 1true 以每隔四秒轮询一次文件系统,确认是否发生更改(不可配置)。

glob 模式Glob patterns

文件系统路径使用名为 glob(或通配)模式 的通配符模式。使用这些模式指定文件的组。两个通配符分别是 *

*匹配当前文件夹级别的任何内容、任何文件名或任何文件扩展名。匹配由文件路径中的 /. 字符终止。

**匹配多个目录级别的任何内容。可用于以递归方式匹配目录层次结构中的许多文件。

glob 模式示例

directory/file.txt匹配特定目录中的特定文件。

directory/*.txt匹配特定目录中带 .txt 扩展名的所有文件。

directory/*/appsettings.json匹配正好位于“目录” 文件夹中下一级目录中的所有 appsettings.json 文件。

directory//.txt*匹配在“目录” 文件夹下任何位置找到的带 .txt 扩展名的所有文件。