ASP.NET Core 中的檔案提供者
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
作者:Steve Smith
ASP.NET Core 透過使用檔案提供者,將檔案系統存取抽象化。 [檔案提供者] 在整個 ASP.NET Core 架構中使用。 例如:
- IWebHostEnvironment 將應用程式的內容根目錄與 Web 根目錄公開為
IFileProvider
型別。 - 靜態檔案中介軟體使用檔案提供者尋找靜態檔案。
- Razor 使用檔案提供者來尋找頁面與檢視。
- .NET Core 工具使用「檔案提供者」與 Glob 模式來指定應該要發佈哪些檔案。
檢視或下載範例程式碼 \(英文\) (如何下載)
檔案提供者介面
主要介面是 IFileProvider。 IFileProvider
公開方法以:
- 取得檔案資訊 (IFileInfo)。
- 取得目錄資訊 (IDirectoryContents)。
- 設定變更通知 (使用 IChangeToken)。
IFileInfo
提供可用來使用檔案的方法與屬性:
- Exists
- IsDirectory
- Name
- Length (以位元組為單位)
- LastModified 日期
您可以使用 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);
上述範例中的型別:
provider
是IFileProvider
。contents
是IDirectoryContents
。fileInfo
是IFileInfo
。
「檔案提供者」可用來逐一查看由 applicationRoot
o所指定的目錄或呼叫 GetFileInfo
以取得檔案的資訊。 Glob 模式無法傳遞至 GetFileInfo
方法。 「檔案提供者」沒有 applicationRoot
外部之項目的存取權。
FileProviderSample
範例應用程式使用 IHostEnvironment.ContentRootFileProvider 在 Startup.ConfigureServices
方法中建立提供者:
var physicalProvider = _env.ContentRootFileProvider;
資訊清單內嵌的檔案提供者
ManifestEmbeddedFileProvider 用來存取內嵌於組件內的檔案。 ManifestEmbeddedFileProvider
使用已編譯到組件中的資訊清單來重新建構內嵌檔案的原始路徑。
若要產生內嵌檔案的資訊清單:
請將
Microsoft.Extensions.FileProviders.Embedded
NuGet 封裝新增至您的專案中。將
<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
範例應用程式中,PhysicalFileProvider
與 ManifestEmbeddedFileProvider
提供檔案給在應用程式的服務容器中註冊的 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
方法:
- 接受檔案路徑字串,該字串可以使用 Glob 模式來指定多個檔案。
- 傳回 IChangeToken。
產生的變更權杖會公開:
- 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
環境變數設定為 1
或 true
,以便每 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 架構中使用:
- IHostingEnvironment 將應用程式的內容根目錄與 Web 根目錄公開為
IFileProvider
型別。 - 靜態檔案中介軟體使用檔案提供者尋找靜態檔案。
- Razor 使用檔案提供者來尋找頁面與檢視。
- .NET Core 工具使用「檔案提供者」與 Glob 模式來指定應該要發佈哪些檔案。
檢視或下載範例程式碼 \(英文\) (如何下載)
檔案提供者介面
主要介面是 IFileProvider。 IFileProvider
公開方法以:
- 取得檔案資訊 (IFileInfo)。
- 取得目錄資訊 (IDirectoryContents)。
- 設定變更通知 (使用 IChangeToken)。
IFileInfo
提供可用來使用檔案的方法與屬性:
- Exists
- IsDirectory
- Name
- Length (以位元組為單位)
- LastModified 日期
您可以使用 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");
上述範例中的型別:
provider
是IFileProvider
。contents
是IDirectoryContents
。fileInfo
是IFileInfo
。
「檔案提供者」可用來逐一查看由 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
執行個體傳遞至其建構函式。
在範例應用程式中,PhysicalFileProvider
與 ManifestEmbeddedFileProvider
提供檔案給在應用程式的服務容器中註冊的 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
環境變數設定為 1
或 true
,以便每 4 秒 (無法設定) 輪詢檔案系統是否有變更。
Glob 模式
檔案系統路徑使用稱為 Glob (或 Glob 處理) 模式的萬用字元模式。 使用這些模式指定檔案群組。 兩種萬用字元為 *
與 **
:
*
符合目前資料夾層級、任何檔案名稱或任何副檔名的任何項目。 相符項是以檔案路徑中的 /
和 .
字元終止。
**
符合多個目錄層級之間的任何項目。 可用來以遞迴方式符合目錄階層內的許多檔案。
Glob 模式範例
directory/file.txt
符合特定目錄中的特定檔案。
directory/*.txt
符合特定目錄中具有 .txt 副檔名的所有檔案。
directory/*/appsettings.json
符合「目錄」資料夾下一層級之目錄中的所有 appsettings.json
檔案。
directory/**/*.txt
符合在「目錄」資料夾下之任何地方所找到的具有 .txt 副檔名的所有檔案。