Dateianbieter in ASP.NET Core

Von Steve Smith

ASP.NET Core abstrahiert Dateisystemzugriff durch die Verwendung von Dateianbietern. Dateianbieter werden im gesamten ASP.NET Core-Framework verwendet. Zum Beispiel:

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Dateianbieterschnittstellen

Die primäre Schnittstelle ist IFileProvider. IFileProvider stellt Methoden zur Verfügung, zum:

IFileInfo stellt Methoden und Eigenschaften für die Arbeit mit Dateien bereit:

Sie können die Datei mithilfe der IFileInfo.CreateReadStream-Methode lesen.

Die Beispiel-App FileProviderSampledemonstriert die Konfiguration eines Dateianbieters in Startup.ConfigureServices für die Verwendung in der gesamten App über Abhängigkeitsinjektion.

Dateianbieterimplementierungen

In der folgenden Tabelle werden Implementierungen von IFileProvider aufgeführt.

Implementierung Beschreibung
Zusammengesetzter Dateianbieter Diese Implementierung wird verwendet, um kombinierten Zugriff auf Dateien und Verzeichnisse von mindestens einem anderen Anbieter bereitzustellen.
Eingebetteter Manifestdateianbieter Diese Implementierung wird für den Zugriff auf in Assemblys eingebettete Dateien verwendet.
Physischer Dateianbieter Diese Implementierung wird für den Zugriff auf die physischen Dateien des Systems verwendet.

Physischer Dateianbieter

Der PhysicalFileProvider ermöglicht den Zugriff auf das physische Dateisystem. PhysicalFileProvider verwendet den System.IO.File-Typ (für den physischen Anbieter). Alle Pfade werden einem Verzeichnis und dessen untergeordneten Elementen zugeordnet. Diese Zuordnung verhindert den Zugriff auf das Dateisystem außerhalb des angegebenen Verzeichnisses und den untergeordneten Elementen. Das häufigste Szenario, in dem ein PhysicalFileProvider erstellt und verwendet wird, ist die Anforderung eines IFileProvider in einem Konstruktor über eine Abhängigkeitsinjektion.

Beim direkten Instanziieren dieses Anbieters ist ein absoluter Verzeichnispfad erforderlich, der als Basispfad für alle Anforderungen über diesen Anbieter dient. Globmuster werden im Verzeichnispfad nicht unterstützt.

Im folgenden Code wird die Verwendung von PhysicalFileProvider zum Abrufen von Verzeichnisinhalten und Dateiinformationen veranschaulicht:

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

Typen im vorherigen Beispiel:

  • provider ist ein IFileProvider.
  • contents ist ein IDirectoryContents.
  • fileInfo ist ein IFileInfo.

Der Dateianbieter kann verwendet werden, um das durch applicationRoot angegebene Verzeichnis zu durchlaufen oder GetFileInfo aufzurufen, um die Informationen einer Datei anzuzeigen. Globmuster können nicht an die GetFileInfo-Methode übergeben werden. Der Dateianbieter hat keinen Zugriff außerhalb des applicationRoot-Verzeichnisses.

Die Beispiel-App FileProviderSample erstellt den Anbieter in der Startup.ConfigureServices-Methode mithilfe von IHostEnvironment.ContentRootFileProvider:

var physicalProvider = _env.ContentRootFileProvider;

Eingebetteter Manifestdateianbieter

Der ManifestEmbeddedFileProvider wird verwendet, um auf Dateien zuzugreifen, die in Assemblys eingebettet sind. Der ManifestEmbeddedFileProvider verwendet ein in die Assembly kompiliertes Manifest, um die ursprünglichen Pfade der eingebetteten Dateien zu rekonstruieren.

So generieren Sie ein Manifest der eingebetteten Dateien:

  1. Fügen Sie Ihrem Projekt das NuGet-Paket Microsoft.Extensions.FileProviders.Embedded hinzu.

  2. Setzen Sie die <GenerateEmbeddedFilesManifest>-Eigenschaft auf true. Geben Sie die einzubettenden Dateien mit <EmbeddedResource> an:

    <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>
    

Verwenden Sie Globmuster, um eine oder mehr Dateien anzugeben, die in die Assembly eingebettet werden sollen.

Die Beispiel-App FileProviderSample erstellt einen ManifestEmbeddedFileProvider und übergibt die aktuell ausgeführte Assembly an den Konstruktor.

Startup.cs:

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

Mit zusätzlichen Überladungen können Sie:

  • Einen relativen Dateipfad angeben.
  • Dateien einem zuletzt geänderten Datum zuordnen.
  • Die eingebettete Ressource benennen, die das eingebettete Dateimanifest enthält.
Überladung Beschreibung
ManifestEmbeddedFileProvider(Assembly, String) Akzeptiert einen optionalen relativen root-Pfadparameter. Geben Sie root an, um Aufrufe von GetDirectoryContents auf die Ressourcen im angegebenen Pfad zu begrenzen.
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) Akzeptiert einen optionalen relativen root-Pfadparameter und einen Datumsparameter für lastModified (DateTimeOffset). Das lastModified-Datum ordnet das letzte Änderungsdatum für die IFileInfo-Instanzen zu, die vom IFileProvider zurückgegeben wurden.
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) Akzeptiert einen optionalen, relativen root-Pfad, ein lastModified-Datum und manifestName-Parameter. manifestName stellt den Namen der eingebetteten Ressource dar, die das Manifest enthält.

Zusammengesetzter Dateianbieter

Der CompositeFileProvider kombiniert IFileProvider-Instanzen, die eine einzelne Schnittstelle zum Arbeiten mit Dateien von mehreren Anbietern verfügbar machen. Beim Erstellen des CompositeFileProvider übergeben Sie eine oder mehrere IFileProvider-Instanzen an seinen Konstruktor.

In der Beispiel-App FileProviderSample stellen ein PhysicalFileProvider und ein ManifestEmbeddedFileProvider Dateien für einen CompositeFileProvider bereit, der im Dienstcontainer der App registriert ist. Der folgende Code befindet sich in der Startup.ConfigureServices-Methode des Projekts:

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

services.AddSingleton<IFileProvider>(compositeProvider);

Überwachen auf Änderungen

Die IFileProvider.Watch-Methode bietet ein Szenario zum Überwachen von Änderungen an Dateien oder Verzeichnissen. Die Watch-Methode:

  • akzeptiert eine Dateipfadzeichenfolge, die Globmuster verwenden kann, um mehrere Dateien anzugeben.
  • Gibt einen IChangeToken zurück.

Das resultierende Änderungstoken stellt Folgendes zur Verfügung:

  • HasChanged: Eine Eigenschaft, die überprüft werden kann, um festzustellen, ob eine Änderung vorgenommen wurde.
  • RegisterChangeCallback: Diese Methode wird aufgerufen, wenn Änderungen an der angegebenen Pfadzeichenfolge erkannt werden. Jedes Änderungstoken ruft nur seine zugeordneten Rückrufe als Antwort auf eine einzelne Änderung auf. Zur Aktivierung einer konstanten Überwachung verwenden Sie eine TaskCompletionSource<TResult> (wie unten dargestellt), oder erstellen Sie IChangeToken-Instanzen nach Änderungen neu.

Die Beispiel-App WatchConsole schreibt eine Nachricht, wenn eine .txt-Datei im Verzeichnis TextFiles geändert wird:

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");
}

Einige Dateisysteme, z.B. Docker-Container und Netzwerkfreigaben, senden Änderungsmeldungen möglicherweise nicht zuverlässig . Legen Sie die DOTNET_USE_POLLING_FILE_WATCHER-Umgebungsvariable auf 1 oder true fest, um das Dateisystem alle 4 Sekunden nach Änderungen zu untersuchen (nicht konfigurierbar).

Globmuster

Dateisystempfade verwenden Platzhaltermuster namens Globmuster. Geben Sie Gruppen von Dateien mit diesen Mustern an. Die zwei Platzhalterzeichen sind * und **:

*
Überprüft alles auf der aktuellen Ordnerebene, jeden Dateinamen oder jede Dateierweiterung. Übereinstimmungen werden durch /- und .-Zeichen im Dateipfad beendet.

**
Überprüft alles auf mehrere Verzeichnisebenen. Kann verwendet werden, um rekursiv eine Übereinstimmung für viele Dateien innerhalb einer Verzeichnishierarchie zu finden.

Die folgende Tabelle enthält gängige Beispiele für Globmuster.

Muster Beschreibung
directory/file.txt Entspricht einer bestimmten Datei in einem bestimmten Verzeichnis.
directory/*.txt Entspricht allen Dateien mit .txt-Erweiterung in einem bestimmten Verzeichnis.
directory/*/appsettings.json Entspricht allen appsettings.json-Dateien in Verzeichnissen auf der nächsttieferen Ebene des directory-Ordners.
directory/**/*.txt Vergleicht alle Dateien mit der Erweiterung .txt, die innerhalb des Ordners directory ermittelt werden.

ASP.NET Core abstrahiert Dateisystemzugriff durch die Verwendung von Dateianbietern. Dateianbieter werden im gesamten ASP.NET Core-Framework verwendet:

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Dateianbieterschnittstellen

Die primäre Schnittstelle ist IFileProvider. IFileProvider stellt Methoden zur Verfügung, zum:

IFileInfo stellt Methoden und Eigenschaften für die Arbeit mit Dateien bereit:

Mithilfe der IFileInfo.CreateReadStream-Methode können Sie die Datei auslesen.

Die Beispiel-App demonstriert die Konfiguration eines Dateianbieters in Startup.ConfigureServices für die Verwendung in der gesamten App über Abhängigkeitsinjektion.

Dateianbieterimplementierungen

Es sind drei Implementierungen von IFileProvider verfügbar.

Implementierung Beschreibung
PhysicalFileProvider Der physische Anbieter wird verwendet, um auf die physischen Systemdateien zuzugreifen.
ManifestEmbeddedFileProvider Der eingebettete Manifesanbieter wird verwendet, um auf Dateien zuzugreifen, die in Assemblys eingebettet sind.
CompositeFileProvider Der zusammengesetzte Anbieter wird verwendet, um kombinierten Zugriff auf Dateien und Verzeichnisse von einem oder mehreren anderen Anbietern bereitzustellen.

PhysicalFileProvider

Der PhysicalFileProvider ermöglicht den Zugriff auf das physische Dateisystem. PhysicalFileProvider verwendet den System.IO.File-Typ (für den physischen Anbieter). Alle Pfade werden einem Verzeichnis und dessen untergeordneten Elementen zugeordnet. Diese Zuordnung verhindert den Zugriff auf das Dateisystem außerhalb des angegebenen Verzeichnisses und den untergeordneten Elementen. Das häufigste Szenario, in dem ein PhysicalFileProvider erstellt und verwendet wird, ist die Anforderung eines IFileProvider in einem Konstruktor über eine Abhängigkeitsinjektion.

Beim direkten Instanziieren dieses Anbieters ist ein Verzeichnispfad erforderlich, der als Basispfad für alle Anforderungen über diesen Anbieter dient.

Der folgende Code zeigt die Erstellung eines PhysicalFileProvider und dessen Verwendung zum Abrufen von Verzeichnisinhalten und Dateiinformationen:

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

Typen im vorherigen Beispiel:

  • provider ist ein IFileProvider.
  • contents ist ein IDirectoryContents.
  • fileInfo ist ein IFileInfo.

Der Dateianbieter kann verwendet werden, um das durch applicationRoot angegebene Verzeichnis zu durchlaufen oder GetFileInfo aufzurufen, um die Informationen einer Datei anzuzeigen. Der Dateianbieter hat keinen Zugriff außerhalb des applicationRoot-Verzeichnisses.

Die Beispiel-App erstellt einen Anbieter in Startup.ConfigureServices-Klasse der App mit IHostingEnvironment.ContentRootFileProvider:

var physicalProvider = _env.ContentRootFileProvider;

ManifestEmbeddedFileProvider

Der ManifestEmbeddedFileProvider wird verwendet, um auf Dateien zuzugreifen, die in Assemblys eingebettet sind. Der ManifestEmbeddedFileProvider verwendet ein in die Assembly kompiliertes Manifest, um die ursprünglichen Pfade der eingebetteten Dateien zu rekonstruieren.

Um ein Manifest der eingebetteten Dateien zu generieren, legen die <GenerateEmbeddedFilesManifest>-Eigenschaft auf true fest. Geben Sie die einzubettenden Dateien mit <EmbeddedResource> an:

<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>

Verwenden Sie Globmuster, um eine oder mehr Dateien anzugeben, die in die Assembly eingebettet werden sollen.

Die Beispiel-App erstellt einen ManifestEmbeddedFileProvider und übergibt die aktuell ausgeführte Assembly an den Konstruktor.

Startup.cs:

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

Mit zusätzlichen Überladungen können Sie:

  • Einen relativen Dateipfad angeben.
  • Dateien einem zuletzt geänderten Datum zuordnen.
  • Die eingebettete Ressource benennen, die das eingebettete Dateimanifest enthält.
Überladung Beschreibung
ManifestEmbeddedFileProvider(Assembly, String) Akzeptiert einen optionalen relativen root-Pfadparameter. Geben Sie root an, um Aufrufe von GetDirectoryContents auf die Ressourcen im angegebenen Pfad zu begrenzen.
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) Akzeptiert einen optionalen relativen root-Pfadparameter und einen Datumsparameter für lastModified (DateTimeOffset). Das lastModified-Datum ordnet das letzte Änderungsdatum für die IFileInfo-Instanzen zu, die vom IFileProvider zurückgegeben wurden.
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) Akzeptiert einen optionalen, relativen root-Pfad, ein lastModified-Datum und manifestName-Parameter. manifestName stellt den Namen der eingebetteten Ressource dar, die das Manifest enthält.

CompositeFileProvider

Der CompositeFileProvider kombiniert IFileProvider-Instanzen, die eine einzelne Schnittstelle zum Arbeiten mit Dateien von mehreren Anbietern verfügbar machen. Beim Erstellen des CompositeFileProvider übergeben Sie eine oder mehrere IFileProvider-Instanzen an seinen Konstruktor.

In der Beispiel-App stellt ein PhysicalFileProvider und ein ManifestEmbeddedFileProvider Dateien an ein CompositeFileProvider, der im Dienstcontainer der App registriert ist:

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

services.AddSingleton<IFileProvider>(compositeProvider);

Überwachen auf Änderungen

Die IFileProvider.Watch-Methode bietet ein Szenario, eine oder mehrere Dateien oder Verzeichnisse auf Änderungen zu überwachen. Watchakzeptiert eine Pfadzeichenfolge, die Globmuster verwenden kann, um mehrere Dateien anzugeben. IChangeToken gibt Watch zurück. Das Änderungstoken macht folgendes verfügbar:

  • HasChanged: Eine Eigenschaft, die überprüft werden kann, um festzustellen, ob eine Änderung vorgenommen wurde.
  • RegisterChangeCallback: Diese Methode wird aufgerufen, wenn Änderungen an der angegebenen Pfadzeichenfolge erkannt werden. Jedes Änderungstoken ruft nur seine zugeordneten Rückrufe als Antwort auf eine einzelne Änderung auf. Zur Aktivierung einer konstanten Überwachung verwenden Sie eine TaskCompletionSource<TResult> (wie unten dargestellt), oder erstellen Sie IChangeToken-Instanzen nach Änderungen neu.

In der Beispiel-App wird die WatchConsole-Konsolen-App konfiguriert, damit sie bei einer Änderung einer Textdatei eine Meldung anzeigt:

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");
}

Einige Dateisysteme, z.B. Docker-Container und Netzwerkfreigaben, senden Änderungsmeldungen möglicherweise nicht zuverlässig . Legen Sie die DOTNET_USE_POLLING_FILE_WATCHER-Umgebungsvariable auf 1 oder true fest, um das Dateisystem alle 4 Sekunden nach Änderungen zu untersuchen (nicht konfigurierbar).

Globmuster

Dateisystempfade verwenden Platzhaltermuster namens Globmuster. Geben Sie Gruppen von Dateien mit diesen Mustern an. Die zwei Platzhalterzeichen sind * und **:

*
Überprüft alles auf der aktuellen Ordnerebene, jeden Dateinamen oder jede Dateierweiterung. Übereinstimmungen werden durch /- und .-Zeichen im Dateipfad beendet.

**
Überprüft alles auf mehrere Verzeichnisebenen. Kann verwendet werden, um rekursiv eine Übereinstimmung für viele Dateien innerhalb einer Verzeichnishierarchie zu finden.

Beispiele für Globmuster

directory/file.txt
Entspricht einer bestimmten Datei in einem bestimmten Verzeichnis.

directory/*.txt
Entspricht allen Dateien mit .txt-Erweiterung in einem bestimmten Verzeichnis.

directory/*/appsettings.json
Entspricht allen appsettings.json-Dateien in Verzeichnissen auf der nächsttieferen Ebene des directory-Ordners.

directory/**/*.txt
Entspricht allen Dateien mit .txt-Erweiterung, die an einer beliebigen Stelle unter dem directory-Ordner gefunden werden.