ASP.NET Core 中的檔案提供者

作者:Steve Smith

ASP.NET Core 透過使用檔案提供者,將檔案系統存取抽象化。 [檔案提供者] 在整個 ASP.NET Core 架構中使用。 例如:

檢視或下載範例程式碼 \(英文\) (如何下載)

檔案提供者介面

主要介面是 IFileProviderIFileProvider 公開方法以:

IFileInfo 提供可用來使用檔案的方法與屬性:

您可以使用 IFileInfo.CreateReadStream 方法從檔案讀取。

FileProviderSample 範例應用程式示範如何在 Startup.ConfigureServices 中設定 [檔案提供者],以透過 dependency injection 在整個應用程式中使用。

檔案提供者實作

以下資料表列出 IFileProvider 的實作。

實作 描述
複合檔案提供者 用來提供來自一或多個其他提供者之檔案和目錄的合併存取。
資訊清單內嵌檔案提供者 用來存取內嵌於組件的檔案。
實體檔案提供者 用來存取系統的實體檔案。

實體檔案提供者

PhysicalFileProvider 提供對實體檔案系統的存取。 PhysicalFileProvider 會使用 System.IO.File 類型 (針對實體提供者) 並將所有路徑的範圍限定為某個目錄與其子系。 此範圍限定動作可防止存取所指定目錄與其子系以外的檔案系統。 建立並使用 PhysicalFileProvider 的最常見情節是透過相依性插入在函式中要求 IFileProvider

當直接具現化此提供者時,會需要一個絕對目錄路徑,而且此目錄路徑會做為使用該提供者發出之所有要求的基礎路徑。 目錄路徑不支援 Glob 模式。

下列程式碼顯示如何使用 PhysicalFileProvider 來取得目錄內容與檔案資訊:

var provider = new PhysicalFileProvider(applicationRoot);
var contents = provider.GetDirectoryContents(string.Empty);
var filePath = Path.Combine("wwwroot", "js", "site.js");
var fileInfo = provider.GetFileInfo(filePath);

上述範例中的型別:

  • providerIFileProvider
  • contentsIDirectoryContents
  • fileInfoIFileInfo

「檔案提供者」可用來逐一查看由 applicationRoot o所指定的目錄或呼叫 GetFileInfo 以取得檔案的資訊。 Glob 模式無法傳遞至 GetFileInfo 方法。 「檔案提供者」沒有 applicationRoot 外部之項目的存取權。

FileProviderSample 範例應用程式使用 IHostEnvironment.ContentRootFileProviderStartup.ConfigureServices 方法中建立提供者:

var physicalProvider = _env.ContentRootFileProvider;

資訊清單內嵌的檔案提供者

ManifestEmbeddedFileProvider 用來存取內嵌於組件內的檔案。 ManifestEmbeddedFileProvider 使用已編譯到組件中的資訊清單來重新建構內嵌檔案的原始路徑。

若要產生內嵌檔案的資訊清單:

  1. 請將 Microsoft.Extensions.FileProviders.Embedded NuGet 封裝新增至您的專案中。

  2. <GenerateEmbeddedFilesManifest> 屬性設為 true。 指定要與 <EmbeddedResource> 內嵌的檔案:

    <Project Sdk="Microsoft.NET.Sdk.Web">
    
      <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
      </PropertyGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.0" />
      </ItemGroup>
    
      <ItemGroup>
        <EmbeddedResource Include="Resource.txt" />
      </ItemGroup>
    
    </Project>
    

使用 Glob 模式來指定一或多個要內嵌到組件中的檔案。

FileProviderSample 範例應用程式會建立 ManifestEmbeddedFileProvider,並將目前執行中組件傳遞到其建構函式。

Startup.cs

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

額外的多載可讓您:

  • 指定相對檔案路徑。
  • 將檔案限定為上次修改日期。
  • 為包內嵌檔案資訊清單的內嵌資源命名。
多載 描述
ManifestEmbeddedFileProvider(Assembly, String) 接受選擇性的 root 相對路徑參數。 指定 root 以將對 GetDirectoryContents 的呼叫限定為所提供路徑下的那些資源。
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) 接受選擇性的 root 相對路徑參數與 lastModified 日期 (DateTimeOffset) 參數。 lastModified 日期會限定為 IFileInfo 執行個體 (由 IFileProvider 所傳回) 的上次修改日期。
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) 接受選擇性的 root 相對路徑、lastModified 日期與 manifestName 參數。 manifestName 代表包含資訊清單之內嵌資源的名稱。

複合檔案提供者

CompositeFileProvider 結合了 IFileProvider 執行個體,並公開單一介面來處理來自多個提供者的檔案。 建立 CompositeFileProvider 時,您可以將一或多個 IFileProvider 執行個體傳遞至其建構函式。

FileProviderSample 範例應用程式中,PhysicalFileProviderManifestEmbeddedFileProvider 提供檔案給在應用程式的服務容器中註冊的 CompositeFileProvider。 下列程式碼可在專案的 Startup.ConfigureServices 方法中找到:

var physicalProvider = _env.ContentRootFileProvider;
var manifestEmbeddedProvider = 
    new ManifestEmbeddedFileProvider(typeof(Program).Assembly);
var compositeProvider = 
    new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);

services.AddSingleton<IFileProvider>(compositeProvider);

監視變更

IFileProvider.Watch 方法提供了一種情節,可用來監看一或多個檔案或目錄是否有變更。 Watch 方法:

產生的變更權杖會公開:

  • HasChanged:可檢查以判斷是否發生變更的屬性。
  • RegisterChangeCallback:當偵測到所指定路徑字串發生變更時要呼叫的項目。 每個變更權杖都只會呼叫其相關聯的回呼,以回應單一變更。 若要啟用持續監視,請使用 TaskCompletionSource<TResult> (如下所示) 或重新建立 IChangeToken 執行個體以回應變更。

每當 TextFiles 目錄中的 .txt 檔案遭到修改時,WatchConsole 範例應用程式就會寫入訊息:

private static readonly string _fileFilter = Path.Combine("TextFiles", "*.txt");

public static void Main(string[] args)
{
    Console.WriteLine($"Monitoring for changes with filter '{_fileFilter}' (Ctrl + C to quit)...");

    while (true)
    {
        MainAsync().GetAwaiter().GetResult();
    }
}

private static async Task MainAsync()
{
    var fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());
    IChangeToken token = fileProvider.Watch(_fileFilter);
    var tcs = new TaskCompletionSource<object>();

    token.RegisterChangeCallback(state =>
        ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);

    await tcs.Task.ConfigureAwait(false);

    Console.WriteLine("file changed");
}

某些檔案系統 (例如 Docker 容器和網路共用) 可能無法可靠地傳送變更通知。 將 DOTNET_USE_POLLING_FILE_WATCHER 環境變數設定為 1true,以便每 4 秒 (無法設定) 輪詢檔案系統是否有變更。

Glob 模式

檔案系統路徑使用稱為 Glob (或 Glob 處理) 模式的萬用字元模式。 使用這些模式指定檔案群組。 兩種萬用字元為 ***

*
符合目前資料夾層級、任何檔案名稱或任何副檔名的任何項目。 相符項是以檔案路徑中的 /. 字元終止。

**
符合多個目錄層級之間的任何項目。 可用來以遞迴方式符合目錄階層內的許多檔案。

下表提供 Glob 模式的常見範例。

模式 描述
directory/file.txt 符合特定目錄中的特定檔案。
directory/*.txt 符合特定目錄中具有 .txt 副檔名的所有檔案。
directory/*/appsettings.json 符合 directory 資料夾下一層級的目錄中的所有 appsettings.json 檔案。
directory/**/*.txt 符合在 directory 資料夾下的任何地方所找到之具有 .txt 副檔名的所有檔案。

ASP.NET Core 透過使用檔案提供者,將檔案系統存取抽象化。 「檔案提供者」在整個 ASP.NET Core 架構中使用:

檢視或下載範例程式碼 \(英文\) (如何下載)

檔案提供者介面

主要介面是 IFileProviderIFileProvider 公開方法以:

IFileInfo 提供可用來使用檔案的方法與屬性:

您可以使用 IFileInfo.CreateReadStream 方法來讀取該檔案。

範例應用程式示範如何在 Startup.ConfigureServices 中設定「檔案提供者」,以透過 dependency injection 在整個應用程式中使用。

檔案提供者實作

我們提供三個 IFileProvider 的實作。

實作 描述
PhysicalFileProvider 實體提供者用來存取系統的實體檔案。
ManifestEmbeddedFileProvider 資訊清單內嵌提供者用來存取內嵌於組件的檔案。
CompositeFileProvider 複合提供者則用來提供對一或多個其他提供者之檔案和目錄的合併存取。

PhysicalFileProvider

PhysicalFileProvider 提供對實體檔案系統的存取。 PhysicalFileProvider 會使用 System.IO.File 類型 (針對實體提供者) 並將所有路徑的範圍限定為某個目錄與其子系。 此範圍限定動作可防止存取所指定目錄與其子系以外的檔案系統。 建立並使用 PhysicalFileProvider 的最常見情節是透過相依性插入在函式中要求 IFileProvider

當直接具現化此提供者時,會需要一個目錄路徑,而且此目錄路徑會做為使用該提供者發出之所有要求的基底路徑。

下列程式碼顯示如何建立 PhysicalFileProvider 並使用它來取得目錄內容與檔案資訊:

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

上述範例中的型別:

  • providerIFileProvider
  • contentsIDirectoryContents
  • fileInfoIFileInfo

「檔案提供者」可用來逐一查看由 applicationRoot o所指定的目錄或呼叫 GetFileInfo 以取得檔案的資訊。 「檔案提供者」沒有 applicationRoot 外部之項目的存取權。

範例應用程式會使用 IHostingEnvironment.ContentRootFileProvider在應用程式的 Startup.ConfigureServices 類別中建立該提供者:

var physicalProvider = _env.ContentRootFileProvider;

ManifestEmbeddedFileProvider

ManifestEmbeddedFileProvider 用來存取內嵌於組件內的檔案。 ManifestEmbeddedFileProvider 使用已編譯到組件中的資訊清單來重新建構內嵌檔案的原始路徑。

若要產生內嵌檔案的資訊清單,請將 <GenerateEmbeddedFilesManifest> 屬性設定為 true。 使用 <EmbeddedResource> 來指定要內嵌的檔案:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Include="Resource.txt" />
  </ItemGroup>

</Project>

使用 Glob 模式來指定一或多個要內嵌到組件中的檔案。

範例應用程式會建立 ManifestEmbeddedFileProvider 並將目前執行中組件傳遞到其建構函式。

Startup.cs

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

額外的多載可讓您:

  • 指定相對檔案路徑。
  • 將檔案限定為上次修改日期。
  • 為包內嵌檔案資訊清單的內嵌資源命名。
多載 描述
ManifestEmbeddedFileProvider(Assembly, String) 接受選擇性的 root 相對路徑參數。 指定 root 以將對 GetDirectoryContents 的呼叫限定為所提供路徑下的那些資源。
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) 接受選擇性的 root 相對路徑參數與 lastModified 日期 (DateTimeOffset) 參數。 lastModified 日期會限定為 IFileInfo 執行個體 (由 IFileProvider 所傳回) 的上次修改日期。
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) 接受選擇性的 root 相對路徑、lastModified 日期與 manifestName 參數。 manifestName 代表包含資訊清單之內嵌資源的名稱。

CompositeFileProvider

CompositeFileProvider 結合了 IFileProvider 執行個體,並公開單一介面來處理來自多個提供者的檔案。 建立 CompositeFileProvider 時,您可以將一或多個 IFileProvider 執行個體傳遞至其建構函式。

在範例應用程式中,PhysicalFileProviderManifestEmbeddedFileProvider 提供檔案給在應用程式的服務容器中註冊的 CompositeFileProvider

var physicalProvider = _env.ContentRootFileProvider;
var manifestEmbeddedProvider = 
    new ManifestEmbeddedFileProvider(typeof(Program).Assembly);
var compositeProvider = 
    new CompositeFileProvider(physicalProvider, manifestEmbeddedProvider);

services.AddSingleton<IFileProvider>(compositeProvider);

監視變更

IFileProvider.Watch 方法提供一種情節,用來監視一或多個檔案或目錄是否有變更。 Watch 接受路徑字串,該字串可以使用 Glob 模式來指定多個檔案。 Watch 會傳回 IChangeToken。 變更權杖會公開:

  • HasChanged:可檢查以判斷是否發生變更的屬性。
  • RegisterChangeCallback:當偵測到所指定路徑字串發生變更時要呼叫的項目。 每個變更權杖都只會呼叫其相關聯的回呼,以回應單一變更。 若要啟用持續監視,請使用 TaskCompletionSource<TResult> (如下所示) 或重新建立 IChangeToken 執行個體以回應變更。

在範例應用程式中,WatchConsole 主控台應用程式是設定為在文字檔案被修改時顯示訊息:

private static PhysicalFileProvider _fileProvider = 
    new PhysicalFileProvider(Directory.GetCurrentDirectory());

public static void Main(string[] args)
{
    Console.WriteLine("Monitoring quotes.txt for changes (Ctrl-c to quit)...");

    while (true)
    {
        MainAsync().GetAwaiter().GetResult();
    }
}

private static async Task MainAsync()
{
    IChangeToken token = _fileProvider.Watch("quotes.txt");
    var tcs = new TaskCompletionSource<object>();

    token.RegisterChangeCallback(state => 
        ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);

    await tcs.Task.ConfigureAwait(false);

    Console.WriteLine("quotes.txt changed");
}

某些檔案系統 (例如 Docker 容器和網路共用) 可能無法可靠地傳送變更通知。 將 DOTNET_USE_POLLING_FILE_WATCHER 環境變數設定為 1true,以便每 4 秒 (無法設定) 輪詢檔案系統是否有變更。

Glob 模式

檔案系統路徑使用稱為 Glob (或 Glob 處理) 模式的萬用字元模式。 使用這些模式指定檔案群組。 兩種萬用字元為 ***

*
符合目前資料夾層級、任何檔案名稱或任何副檔名的任何項目。 相符項是以檔案路徑中的 /. 字元終止。

**
符合多個目錄層級之間的任何項目。 可用來以遞迴方式符合目錄階層內的許多檔案。

Glob 模式範例

directory/file.txt
符合特定目錄中的特定檔案。

directory/*.txt
符合特定目錄中具有 .txt 副檔名的所有檔案。

directory/*/appsettings.json
符合「目錄」資料夾下一層級之目錄中的所有 appsettings.json 檔案。

directory/**/*.txt
符合在「目錄」資料夾下之任何地方所找到的具有 .txt 副檔名的所有檔案。