Condividi tramite


Provider di file in ASP.NET Core

Di Steve Smith

ASP.NET Core astrae l'accesso al file system tramite l'utilizzo di provider di file. I provider di file vengono usati in tutto il framework ASP.NET Core. Ad esempio:

  • IWebHostEnvironmentespone la radice del contenuto e la radice Web dell'app come IFileProvider tipi.
  • Il middleware dei file statici usa i provider di file per trovare i file statici.
  • Razor usa provider di file per individuare pagine e visualizzazioni.
  • Gli strumenti .NET Core usano i provider di file e i criteri GLOB per specificare i file da pubblicare.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Interfacce del provider di file

L'interfaccia primaria è IFileProvider. IFileProvider espone metodi per:

IFileInfo fornisce metodi e proprietà per l'uso di file:

È possibile leggere dal file usando il IFileInfo.CreateReadStream metodo .

L'app FileProviderSample di esempio illustra come configurare un provider di file in per l'uso in Startup.ConfigureServices tutta l'app tramite inserimento delle dipendenze.

Implementazioni dei provider di file

Nella tabella seguente sono elencate le implementazioni di IFileProvider.

Implementazione Descrizione
Provider di file compositi Usato per fornire l'accesso combinato a file e directory da uno o più provider.
Provider di file incorporati del manifesto Usato per accedere ai file incorporati negli assembly.
Provider di file fisici Usato per accedere ai file fisici del sistema.

Provider di file fisici

PhysicalFileProvider consente di accedere al file system fisico. PhysicalFileProvider usa il tipo System.IO.File (per il provider fisico) e definisce una directory e i relativi elementi figlio come ambito per tutti i percorsi. La definizione dell'ambito impedisce l'accesso al file system al di fuori della directory specificata e dei relativi elementi figlio. Lo scenario più comune per la creazione e l'uso di un PhysicalFileProvider consiste nel richiedere un oggetto IFileProvider in un costruttore tramite inserimento delle dipendenze.

Quando si crea direttamente un'istanza di questo provider, è necessario un percorso di directory assoluto e funge da percorso di base per tutte le richieste effettuate usando il provider. I modelli Glob non sono supportati nel percorso della directory.

Il codice seguente illustra come usare PhysicalFileProvider per ottenere il contenuto della directory e le informazioni sui file:

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

Tipi nell'esempio precedente:

  • provider è di tipo IFileProvider.
  • contents è di tipo IDirectoryContents.
  • fileInfo è di tipo IFileInfo.

Il provider di file può essere usato per scorrere la directory specificata da applicationRoot oppure per chiamare GetFileInfo per ottenere informazioni su un file. I modelli Glob non possono essere passati al GetFileInfo metodo . Il provider di file non ha accesso all'esterno della directory applicationRoot.

L'app FileProviderSample di esempio crea il provider nel Startup.ConfigureServices metodo usando IHostEnvironment.ContentRootFileProvider:

var physicalProvider = _env.ContentRootFileProvider;

Provider di file incorporati del manifesto

ManifestEmbeddedFileProvider consente di accedere ai file incorporati negli assembly. ManifestEmbeddedFileProvider usa un manifesto compilato nell'assembly per ricostruire i percorsi originali dei file incorporati.

Per generare un manifesto dei file incorporati:

  1. Aggiungere il pacchetto NuGet Microsoft.Extensions.FileProviders.Embedded al progetto.

  2. Impostare la proprietà <GenerateEmbeddedFilesManifest> su true. Specificare i file da incorporare con <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>
    

Usare modelli GLOB per specificare uno o più file da incorporare nell'assembly.

L'app FileProviderSample di esempio crea un oggetto ManifestEmbeddedFileProvider e passa l'assembly attualmente in esecuzione al relativo costruttore.

Startup.cs:

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

Overload aggiuntivi consentono di:

  • Specificare un percorso di file relativo.
  • Definire la data dell'ultima modifica come ambito dei file.
  • Assegnare un nome alla risorsa incorporata contenente il manifesto dei file incorporati.
Overload Descrizione
ManifestEmbeddedFileProvider(Assembly, String) Accetta un parametro di percorso relativo root facoltativo. Specificare root per definire come ambito delle chiamate a GetDirectoryContents le risorse incluse nel percorso specificato.
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) Accetta un parametro di percorso relativo root facoltativo e un parametro di data lastModified (DateTimeOffset). La data lastModified definisce la data dell'ultima modifica come ambito per le istanze di IFileInfo restituite da IFileProvider.
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) Accetta un parametro di percorso relativo root facoltativo, un parametro di data lastModified e il parametro manifestName. manifestName rappresenta il nome della risorsa incorporata contenente il manifesto.

Provider di file compositi

CompositeFileProvider combina le istanze IFileProvider esponendo una sola interfaccia per l'uso dei file di più provider. Quando si crea CompositeFileProvider, passare una o più istanze IFileProvider al relativo costruttore.

Nell'app FileProviderSample di esempio un PhysicalFileProvider e un ManifestEmbeddedFileProvider oggetto forniscono file a un CompositeFileProvider oggetto registrato nel contenitore del servizio dell'app. Il codice seguente si trova nel metodo del Startup.ConfigureServices progetto:

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

services.AddSingleton<IFileProvider>(compositeProvider);

Controllo delle modifiche

Il IFileProvider.Watch metodo fornisce uno scenario per controllare una o più directory o file per le modifiche. Il metodo Watch:

  • Accetta una stringa di percorso di file, che può usare modelli GLOB per specificare più file.
  • Restituisce un valore IChangeToken.

Il token di modifica risultante espone:

  • HasChanged: proprietà che può essere controllata per determinare se si è verificata una modifica.
  • RegisterChangeCallback: chiamato quando vengono rilevate modifiche alla stringa di percorso specificata. Ogni token di modifica chiama solo il relativo callback associato in risposta a una singola modifica. Per abilitare un monitoraggio continuo, usare TaskCompletionSource<TResult> come illustrato di seguito oppure ricreare istanze di IChangeToken in risposta alle modifiche.

L'app WatchConsole di esempio scrive un messaggio ogni volta che viene modificato un .txt file nella TextFiles directory:

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

È possibile che alcuni file system, ad esempio i contenitori Docker e le condivisioni di rete, non inviino sempre le notifiche di modifica. Impostare la variabile di ambiente DOTNET_USE_POLLING_FILE_WATCHER su 1 o true per eseguire il polling delle modifiche nel file system ogni quattro secondi (intervallo non configurabile).

Modelli GLOB

Nei percorsi del file system vengono usati criteri con caratteri jolly chiamati criteri GLOB (o globbing). Specificare gruppi di file con questi criteri. I due caratteri jolly sono * e **:

*
Cerca qualsiasi elemento a livello della cartella corrente, qualsiasi nome di file o qualsiasi estensione di file. Le corrispondenze vengono terminate con i caratteri / e . nel percorso dei file.

**
Cerca qualsiasi elemento in più livelli di directory. Può essere usato per cercare in modo ricorsivo numerosi file all'interno di una gerarchia di directory.

La tabella seguente fornisce esempi comuni di modelli glob.

Modello Descrizione
directory/file.txt Cerca un file specifico in una directory specifica.
directory/*.txt Cerca tutti i file con estensione .txt in una directory specifica.
directory/*/appsettings.json Corrisponde a tutti i appsettings.json file nelle directory esattamente un livello inferiore alla directory cartella.
directory/**/*.txt Trova la corrispondenza di tutti i file con un'estensione .txt disponibile in qualsiasi punto della directory cartella.

ASP.NET Core astrae l'accesso al file system tramite l'utilizzo di provider di file. I provider di file vengono usati in tutto il framework di ASP.NET Core:

  • IHostingEnvironmentespone la radice del contenuto e la radice Web dell'app come IFileProvider tipi.
  • Il middleware dei file statici usa i provider di file per trovare i file statici.
  • Razor usa provider di file per individuare pagine e visualizzazioni.
  • Gli strumenti .NET Core usano i provider di file e i criteri GLOB per specificare i file da pubblicare.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Interfacce del provider di file

L'interfaccia primaria è IFileProvider. IFileProvider espone metodi per:

IFileInfo fornisce metodi e proprietà per l'uso di file:

È possibile leggere dal file usando il metodo IFileInfo.CreateReadStream.

L'app di esempio dimostra come configurare un provider di file in Startup.ConfigureServices da usare in tutta l'app tramite inserimento delle dipendenze.

Implementazioni dei provider di file

Sono disponibili tre implementazioni di IFileProvider.

Implementazione Descrizione
PhysicalFileProvider Il provider fisico viene usato per accedere ai file fisici del sistema.
ManifestEmbeddedFileProvider Il provider incorporato nel manifesto viene usato per accedere ai file incorporati negli assembly.
CompositeFileProvider Il provider composito consente di offrire un accesso combinato a file e directory da uno o più provider.

PhysicalFileProvider

PhysicalFileProvider consente di accedere al file system fisico. PhysicalFileProvider usa il tipo System.IO.File (per il provider fisico) e definisce una directory e i relativi elementi figlio come ambito per tutti i percorsi. La definizione dell'ambito impedisce l'accesso al file system al di fuori della directory specificata e dei relativi elementi figlio. Lo scenario più comune per la creazione e l'uso di un PhysicalFileProvider consiste nel richiedere un oggetto IFileProvider in un costruttore tramite inserimento delle dipendenze.

Per la creazione diretta di un'istanza di questo provider, è richiesto un percorso di directory che viene usato come percorso di base per tutte le richieste effettuate tramite il provider.

Il codice seguente illustra come creare un PhysicalFileProvider e usarlo per ottenere il contenuto della directory e informazioni sui file:

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

Tipi nell'esempio precedente:

  • provider è di tipo IFileProvider.
  • contents è di tipo IDirectoryContents.
  • fileInfo è di tipo IFileInfo.

Il provider di file può essere usato per scorrere la directory specificata da applicationRoot oppure per chiamare GetFileInfo per ottenere informazioni su un file. Il provider di file non ha accesso all'esterno della directory applicationRoot.

L'app di esempio crea il provider nella classe Startup.ConfigureServices dell'app usando IHostingEnvironment.ContentRootFileProvider:

var physicalProvider = _env.ContentRootFileProvider;

ManifestEmbeddedFileProvider

ManifestEmbeddedFileProvider consente di accedere ai file incorporati negli assembly. ManifestEmbeddedFileProvider usa un manifesto compilato nell'assembly per ricostruire i percorsi originali dei file incorporati.

Per generare un manifesto dei file incorporati, impostare la proprietà <GenerateEmbeddedFilesManifest> su true. Specificare i file da incorporare con <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>

Usare modelli GLOB per specificare uno o più file da incorporare nell'assembly.

L'app di esempio crea un ManifestEmbeddedFileProvider e passa l'assembly attualmente in esecuzione al rispettivo costruttore.

Startup.cs:

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

Overload aggiuntivi consentono di:

  • Specificare un percorso di file relativo.
  • Definire la data dell'ultima modifica come ambito dei file.
  • Assegnare un nome alla risorsa incorporata contenente il manifesto dei file incorporati.
Overload Descrizione
ManifestEmbeddedFileProvider(Assembly, String) Accetta un parametro di percorso relativo root facoltativo. Specificare root per definire come ambito delle chiamate a GetDirectoryContents le risorse incluse nel percorso specificato.
ManifestEmbeddedFileProvider(Assembly, String, DateTimeOffset) Accetta un parametro di percorso relativo root facoltativo e un parametro di data lastModified (DateTimeOffset). La data lastModified definisce la data dell'ultima modifica come ambito per le istanze di IFileInfo restituite da IFileProvider.
ManifestEmbeddedFileProvider(Assembly, String, String, DateTimeOffset) Accetta un parametro di percorso relativo root facoltativo, un parametro di data lastModified e il parametro manifestName. manifestName rappresenta il nome della risorsa incorporata contenente il manifesto.

CompositeFileProvider

CompositeFileProvider combina le istanze IFileProvider esponendo una sola interfaccia per l'uso dei file di più provider. Quando si crea CompositeFileProvider, passare una o più istanze IFileProvider al relativo costruttore.

Nell'app di esempio, un PhysicalFileProvider e un ManifestEmbeddedFileProvider forniscono i file a un CompositeFileProvider registrato nel contenitore dei servizi dell'app:

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

services.AddSingleton<IFileProvider>(compositeProvider);

Controllo delle modifiche

Il metodo IFileProvider.Watch consente di controllare uno o più file o directory per il rilevamento delle modifiche. Watch accetta una stringa di percorso in cui è possibile usare criteri GLOB per specificare più file. Watch restituisce un oggetto IChangeToken. Il token di modifica espone:

  • HasChanged: proprietà che può essere controllata per determinare se si è verificata una modifica.
  • RegisterChangeCallback: chiamato quando vengono rilevate modifiche alla stringa di percorso specificata. Ogni token di modifica chiama solo il relativo callback associato in risposta a una singola modifica. Per abilitare un monitoraggio continuo, usare TaskCompletionSource<TResult> come illustrato di seguito oppure ricreare istanze di IChangeToken in risposta alle modifiche.

Nell'app di esempio, l'app console WatchConsole viene configurata per visualizzare un messaggio quando viene modificato un file di testo:

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

È possibile che alcuni file system, ad esempio i contenitori Docker e le condivisioni di rete, non inviino sempre le notifiche di modifica. Impostare la variabile di ambiente DOTNET_USE_POLLING_FILE_WATCHER su 1 o true per eseguire il polling delle modifiche nel file system ogni quattro secondi (intervallo non configurabile).

Modelli GLOB

Nei percorsi del file system vengono usati criteri con caratteri jolly chiamati criteri GLOB (o globbing). Specificare gruppi di file con questi criteri. I due caratteri jolly sono * e **:

*
Cerca qualsiasi elemento a livello della cartella corrente, qualsiasi nome di file o qualsiasi estensione di file. Le corrispondenze vengono terminate con i caratteri / e . nel percorso dei file.

**
Cerca qualsiasi elemento in più livelli di directory. Può essere usato per cercare in modo ricorsivo numerosi file all'interno di una gerarchia di directory.

Esempi di criteri GLOB

directory/file.txt
Cerca un file specifico in una directory specifica.

directory/*.txt
Cerca tutti i file con estensione txt in una directory specifica.

directory/*/appsettings.json
Cerca tutti i file appsettings.json nelle directory esattamente un livello sotto la cartella directory.

directory/**/*.txt
Cerca tutti i file con estensione txt che si trovano in qualsiasi posizione nella cartella directory.