Partager via


Fichiers statiques dans ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.

Importante

Ces informations concernent un produit en version préliminaire, qui pourrait être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 9 de cet article.

Par Rick Anderson

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateBuilder définit le répertoire actif comme racine du contenu :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Servir des fichiers dans le répertoire racine du web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Program.cs, ce qui permet de délivrer les fichiers statiques :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

La surcharge de la méthode UseStaticFiles sans paramètre marque les fichiers de la racine Web comme étant accessibles. Ce qui suit fait référence à wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le balisage précédent, le caractère tilde ~ pointe vers la racine web.

Servir des fichiers en dehors du répertoire racine du site web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une requête vers https://<hostname>/StaticFiles/images/red-rose.jpg sert le fichier red-rose.jpg.

Le balisage suivant fait référence à MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Pour délivrer des fichiers à partir de plusieurs emplacements, consultez Délivrer des fichiers à partir de plusieurs emplacements.

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent rend les fichiers statiques accessibles publiquement dans le cache local pendant une semaine (604800 secondes).

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points de terminaison tels que les contrôleurs, les pages Razor, etc. qui spécifient leurs propres exigences en matière d'autorisation n'utilisent pas la stratégie d'autorisation de secours. Par exemple, les pages Razor, les contrôleurs ou les méthodes d'action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l'attribut d'autorisation appliqué plutôt que la stratégie d'autorisation de repli.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.

  • Les servir via une méthode d'action à laquelle l'autorisation est appliquée et renvoyer un objet FileResult :

    [Authorize]
    public class BannerImageModel : PageModel
    {
        private readonly IWebHostEnvironment _env;
    
        public BannerImageModel(IWebHostEnvironment env) =>
            _env = env;
    
        public PhysicalFileResult OnGet()
        {
            var filePath = Path.Combine(
                    _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
    
            return PhysicalFile(filePath, "image/jpeg");
        }
    }
    

L’approche précédente nécessite une page ou un point de terminaison par fichier. Le code suivant retourne des fichiers ou charge des fichiers pour les utilisateurs authentifiés :

app.MapGet("/files/{fileName}",  IResult (string fileName) => 
    {
        var filePath = GetOrCreateFilePath(fileName);

        if (File.Exists(filePath))
        {
            return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
        }

        return TypedResults.NotFound("No file found with the supplied file name");
    })
    .WithName("GetFileByName")
    .RequireAuthorization("AuthenticatedUsers");

// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
    {
        // Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
        // Take a look at the `Utilities.IsFileValid` method that takes an IFormFile and validates its signature within the AllowedFileSignatures
        
        var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
        await SaveFileWithCustomFileName(file, fileSaveName);
        
        context.Response.Headers.Append("Location", linker.GetPathByName(context, "GetFileByName", new { fileName = fileSaveName}));
        return TypedResults.Ok("File Uploaded Successfully!");
    })
    .RequireAuthorization("AdminsOnly");

app.Run();

Pour obtenir l’exemple complet, consultez le dossier GitHub StaticFileAuth.

Exploration de répertoires

La navigation dans les répertoires permet d'afficher la liste des répertoires dans les répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec AddDirectoryBrowser et UseDirectoryBrowser :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

AddDirectoryBrowserajoute les services nécessaires pour l’intergiciel d’exploration des répertoires, notamment HtmlEncoder. Ces services peuvent être ajoutés par d’autres appels, tels que AddRazorPages, mais nous vous recommandons d’appeler AddDirectoryBrowser pour garantir que les services sont ajoutés dans toutes les applications.

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédents, les URL sont résolues comme suit :

URI Réponse
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/) à moins que l’option RedirectToAppendTrailingSlash de DefaultFilesOptions soit utilisée.

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

Considérez la page Razor suivante qui affiche le fichier /MyStaticFiles/image3.png :

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. L’exemple suivant appelle UseStaticFiles deux fois pour délivrer des fichiers à partir de wwwroot et de MyStaticFiles :

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Utilisation du code précédent :

Le code suivant met à jour le WebRootFileProvider, ce qui permet à l'Image Tag Helper de fournir une version :

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Remarque

L’approche précédente s’applique aux applications Razor Pages et MVC. Pour des conseils qui s'appliquent aux Blazor Web Apps, voir ASP.NET Core Blazorfichiers statiques.

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows est insensible à la casse, mais macOS et Linux ne le sont pas.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Délivrez des fichiers en dehors de wwwroot en mettant à jour IWebHostEnvironment.WebRootPath

Quand IWebHostEnvironment.WebRootPath est défini sur un dossier autre que wwwroot :

  • Dans l’environnement de développement, les ressources statiques trouvées dans wwwroot et dans la mise à jour de IWebHostEnvironment.WebRootPath sont délivrées à partir de wwwroot.
  • Dans tout environnement autre que celui de développement, les ressources statiques en double sont délivrées à partir du dossier IWebHostEnvironment.WebRootPath mis à jour.

Considérez une application web créée avec le modèle web vide :

  • Contenant un fichier Index.html dans wwwroot et wwwroot-custom.

  • Avec le fichier Program.cs mis à jour suivant qui définit WebRootPath = "wwwroot-custom" :

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dans le code précédent, les requêtes vers / :

  • Dans l'environnement de développement, retourner wwwroot/Index.html
  • Dans tout environnement autre que le développement, retourner wwwroot-custom/Index.html

Pour vous assurer que les ressources à partir de wwwroot-custom sont retournées, utilisez l’une des approches suivantes :

  • Supprimer les ressources nommées en double dans wwwroot

  • Définissez "ASPNETCORE_ENVIRONMENT" dans Properties/launchSettings.json sur n’importe quelle valeur autre que "Development".

  • Désactivez complètement les ressources web statiques en définissant <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dans le fichier projet. AVERTISSEMENT, la désactivation des ressources web statiques désactive les bibliothèques de classes Razor.

  • Ajoutez le code JSON suivant au fichier projet :

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Le code suivant met à jour IWebHostEnvironment.WebRootPath vers une valeur de non-développement, garantissant que le contenu en double est retourné à partir de wwwroot-custom plutôt que wwwroot :

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Ressources supplémentaires

Par Rick Anderson et Kirk Larkin

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateBuilder définit le répertoire actif comme racine du contenu :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Servez les fichiers dans la racine du Web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Program.cs, ce qui permet de délivrer les fichiers statiques :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

La surcharge de la méthode UseStaticFiles sans paramètre marque les fichiers de la racine Web comme étant accessibles. Le balisage suivant fait référence à wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le balisage précédent, le caractère tilde ~ pointe vers la racine web.

Servir des fichiers en dehors du répertoire racine du serveur web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une requête vers https://<hostname>/StaticFiles/images/red-rose.jpg sert le fichier red-rose.jpg.

Le balisage suivant fait référence à MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Pour délivrer des fichiers à partir de plusieurs emplacements, consultez Délivrer des fichiers à partir de plusieurs emplacements.

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
             "Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
    }
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent rend les fichiers statiques accessibles publiquement dans le cache local pendant une semaine (604800 secondes).

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles"
});

app.MapRazorPages();

app.Run();

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points d'accès tels que les contrôleurs, Razor Pages, qui spécifient leurs propres exigences d’autorisation, n’utilisent pas la politique d’autorisation par défaut. Par exemple, les pages Razor, les contrôleurs ou les méthodes d'action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l'attribut d'autorisation appliqué plutôt que la stratégie d'autorisation de repli.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.
  • Les servir via une méthode d'action à laquelle l'autorisation est appliquée et renvoyer un objet FileResult :
[Authorize]
public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) =>
        _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
                _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

Exploration de répertoires

Parcourir les répertoires permet d'établir une liste de répertoires à l'intérieur de répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec AddDirectoryBrowser et UseDirectoryBrowser :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";

// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

AddDirectoryBrowserajoute les services nécessaires pour l’intergiciel d’exploration des répertoires, notamment HtmlEncoder. Ces services peuvent être ajoutés par d’autres appels, tels que AddRazorPages, mais nous vous recommandons d’appeler AddDirectoryBrowser pour garantir que les services sont ajoutés dans toutes les applications.

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseDefaultFiles();

app.UseStaticFiles();
app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);

app.UseStaticFiles();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFileServer(enableDirectoryBrowsing: true);

app.UseRouting();

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddDirectoryBrowser();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
           Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
    RequestPath = "/StaticFiles",
    EnableDirectoryBrowsing = true
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédents, les URL sont résolues comme suit :

URI Réponse
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/) à moins que l’option RedirectToAppendTrailingSlash de DefaultFilesOptions soit utilisée.

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

app.UseAuthorization();

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

Considérez la page Razor suivante qui affiche le fichier /MyStaticFiles/image3.png :

@page

<p> Test /MyStaticFiles/image3.png</p>

<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. L’exemple suivant appelle UseStaticFiles deux fois pour délivrer des fichiers à partir de wwwroot et de MyStaticFiles :

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});

Utilisation du code précédent :

Le code suivant met à jour le WebRootFileProvider, ce qui permet au Tag Helper d’Image de fournir une version :

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
  Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider,
                                                  newPathProvider);

// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;

app.UseStaticFiles();

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows est insensible à la casse, mais macOS et Linux ne le sont pas.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Délivrez des fichiers en dehors de wwwroot en mettant à jour IWebHostEnvironment.WebRootPath

Quand IWebHostEnvironment.WebRootPath est défini sur un dossier autre que wwwroot :

  • Dans l’environnement de développement, les ressources statiques trouvées dans wwwroot et dans la mise à jour de IWebHostEnvironment.WebRootPath sont délivrées à partir de wwwroot.
  • Dans tout environnement autre que celui de développement, les ressources statiques en double sont délivrées à partir du dossier IWebHostEnvironment.WebRootPath mis à jour.

Considérez une application web créée avec le modèle web vide :

  • Contenant un fichier Index.html dans wwwroot et wwwroot-custom.

  • Avec le fichier Program.cs mis à jour suivant qui définit WebRootPath = "wwwroot-custom" :

    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
        Args = args,
        // Look for static files in "wwwroot-custom"
        WebRootPath = "wwwroot-custom"
    });
    
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.Run();
    

Dans le code précédent, les requêtes vers / :

  • Dans l'environnement de développement, retourner wwwroot/Index.html
  • Dans tout environnement autre que le développement, retourner wwwroot-custom/Index.html

Pour vous assurer que les ressources à partir de wwwroot-custom sont retournées, utilisez l’une des approches suivantes :

  • Supprimer les ressources nommées en double dans wwwroot

  • Définissez "ASPNETCORE_ENVIRONMENT" dans Properties/launchSettings.json sur n’importe quelle valeur autre que "Development".

  • Désactivez complètement les ressources web statiques en définissant <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> dans le fichier projet. AVERTISSEMENT, la désactivation des ressources web statiques désactive les bibliothèques de classes Razor.

  • Ajoutez le code JSON suivant au fichier projet :

    <ItemGroup>
        <Content Remove="wwwroot\**" />
    </ItemGroup>
    

Le code suivant met à jour IWebHostEnvironment.WebRootPath vers une valeur de non-développement, garantissant que le contenu en double est retourné à partir de wwwroot-custom plutôt que wwwroot :

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    // Examine Hosting environment: logging value
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

var app = builder.Build();

app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
      Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
      app.Environment.IsDevelopment().ToString());

app.UseDefaultFiles();
app.UseStaticFiles();

app.Run();

Ressources supplémentaires

Par Rick Anderson et Kirk Larkin

Les fichiers statiques, comme les fichiers HTML, CSS, images et JavaScript, sont des ressources qu’une application ASP.NET Core délivre directement aux clients, par défaut.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Délivrer des fichiers statiques

Les fichiers statiques sont stockés dans le répertoire racine web du projet. Le répertoire par défaut est {content root}/wwwroot, mais il peut être modifié avec la méthode UseWebRoot. Pour plus d’informations, consultez Racine de contenu et Racine web.

La méthode CreateDefaultBuilder définit le répertoire actif comme racine du contenu :

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Le code précédent a été créé avec le modèle d’application web.

Les fichiers statiques sont accessibles via un chemin relatif à la racine web. Par exemple, les modèles de projet Application web contiennent plusieurs dossiers dans le dossier wwwroot :

  • wwwroot
    • css
    • js
    • lib

Envisagez de créer le dossier wwwroot/images et d’ajouter le fichier wwwroot/images/MyImage.jpg. Le format URI pour accéder à un fichier dans le dossier images est https://<hostname>/images/<image_file_name>. Par exemple, https://localhost:5001/images/MyImage.jpg

Servez les fichiers dans la racine du Web

Les modèles d’application web par défaut appellent la méthode UseStaticFiles dans Startup.Configure, ce qui permet de délivrer les fichiers statiques :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

La surcharge de la méthode UseStaticFiles sans paramètre marque les fichiers de la racine Web comme étant accessibles. Le balisage suivant fait référence à wwwroot/images/MyImage.jpg :

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

Dans le code précédent, le caractère tilde ~/ pointe vers la racine web.

Délivrer des fichiers en dehors de la racine web

Considérez une hiérarchie de répertoires dans laquelle les fichiers statiques à délivrer se trouvent en dehors de la racine web :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

Une demande peut accéder au fichier red-rose.jpg en configurant l’intergiciel de fichiers statiques comme suit :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Dans le code précédent, la hiérarchie de répertoires MyStaticFiles est exposée publiquement via le segment d’URI StaticFiles. Une requête vers https://<hostname>/StaticFiles/images/red-rose.jpg sert le fichier red-rose.jpg.

Le texte suivant fait référence à MyStaticFiles/images/red-rose.jpg :

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

Définir des en-têtes de réponse HTTP

Un objet StaticFileOptions peut être utilisé pour définir des en-têtes de réponse HTTP. En plus de configurer la possibilité de délivrer des fichiers statiques à partir de la racine web, le code suivant définit l’en-tête Cache-Control :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    const string cacheMaxAge = "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append(
                 "Cache-Control", $"public, max-age={cacheMaxAge}");
        }
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code précédent définit l’âge maximal à 604800 secondes (7 jours).

En-têtes de réponse montrant que l’en-tête Cache-Control a été ajouté

Autorisations des fichiers statiques

Les modèles ASP.NET Core appellent UseStaticFiles avant d’appeler UseAuthorization. La plupart des applications suivent ce modèle. Quand l’intergiciel de fichiers statiques est appelé avant l’intergiciel d’autorisation :

  • Aucune vérification d’autorisation n’est effectuée sur les fichiers statiques.
  • Les fichiers statiques délivrés par l’intergiciel de fichiers statiques, tels que ceux sous wwwroot, sont accessibles publiquement.

Pour délivrer des fichiers statiques en fonction d’une autorisation :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // wwwroot css, JavaScript, and images don't require authentication.
    app.UseStaticFiles();   

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
                     Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();

        services.AddAuthorization(options =>
        {
            options.FallbackPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
        });
    }

    // Remaining code ommitted for brevity.

Dans le code précédent, la stratégie d’autorisation de secours exige que tous les utilisateurs soient authentifiés. Les points de terminaison tels que les contrôleurs, les pages Razor, etc. qui spécifient leurs propres exigences en matière d'autorisation n'utilisent pas la stratégie d'autorisation de secours. Par exemple, les pages Razor, les contrôleurs ou les méthodes d'action avec [AllowAnonymous] ou [Authorize(PolicyName="MyPolicy")] utilisent l'attribut d'autorisation appliqué plutôt que la stratégie d'autorisation de repli.

RequireAuthenticatedUser ajoute DenyAnonymousAuthorizationRequirement à l’instance actuelle, ce qui impose l’authentification de l’utilisateur actuel.

Les ressources statiques sous wwwroot sont accessibles publiquement, car l’intergiciel de fichiers statiques par défaut (app.UseStaticFiles();) est appelé avant UseAuthentication. Les ressources statiques figurant dans le dossier MyStaticFiles nécessitent une authentification. Cet exemple de code illustre ceci.

Une autre approche pour traiter les fichiers en fonction de l’autorisation consiste à :

  • Les stocker en dehors de wwwroot et de tout répertoire accessible à l’intergiciel de fichiers statiques.
  • Les servir via une méthode d'action à laquelle l'autorisation est appliquée et renvoyer un objet FileResult :
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

Exploration de répertoires

La navigation dans les répertoires permet d'afficher le contenu des répertoires spécifiés.

L’exploration des répertoires est désactivée par défaut pour des raisons de sécurité. Pour plus d’informations, consultez Considérations relatives à la sécurité des fichiers statiques.

Activez l’exploration des répertoires avec :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code précédent permet l’exploration des répertoires du dossier wwwroot/images en utilisant l’URL https://<hostname>/MyImages, avec des liens vers chaque fichier et dossier :

exploration de répertoires

Délivrer des documents par défaut

La définition d’une page par défaut fournit aux visiteurs un point de départ sur un site. Pour délivrer un fichier par défaut à partir de wwwroot sans exiger que l’URL de la demande inclue le nom du fichier, appelez la méthode UseDefaultFiles :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseDefaultFiles doit être appelé avant UseStaticFiles pour délivrer le fichier par défaut. UseDefaultFiles est un module de réécriture d’URL qui ne délivre pas le fichier.

Avec UseDefaultFiles, les demandes effectuées sur un dossier dans wwwroot recherchent :

  • default.htm
  • default.html
  • index.htm
  • index.html

Le premier fichier trouvé dans la liste est délivré comme si la demande incluait le nom du fichier. L’URL du navigateur continue de refléter l’URI demandé.

Le code suivant change le nom de fichier par défaut en mydefault.html :

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    var options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

UseFileServer pour les documents par défaut

UseFileServer combine les fonctionnalités de UseStaticFiles, de UseDefaultFiles et éventuellement de UseDirectoryBrowser.

Appelez app.UseFileServer pour activer la possibilité de délivrer des fichiers statiques et le fichier par défaut. L’exploration des répertoires n’est pas activée. Le code suivant montre Startup.Configure avec UseFileServer :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires :

app.UseFileServer(enableDirectoryBrowsing: true);

Le code suivant montre Startup.Configure avec le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer(enableDirectoryBrowsing: true);

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Considérez la hiérarchie de répertoires suivante :

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

Le code suivant active la possibilité de délivrer des fichiers statiques, le fichier par défaut et l’exploration des répertoires de MyStaticFiles :

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(); // For the wwwroot folder.

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

AddDirectoryBrowser doit être appelé quand la valeur de la propriété EnableDirectoryBrowsing est true.

En utilisant la hiérarchie de fichiers et le code précédent, les URL sont résolues comme suit :

URI Réponse
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

Si aucun fichier nommé par défaut n’existe dans le répertoire MyStaticFiles, https://<hostname>/StaticFiles retourne la liste des répertoires avec des liens interactifs :

Liste des fichiers statiques

UseDefaultFiles et UseDirectoryBrowser effectuent une redirection côté client à partir de l’URI cible sans / de fin, vers l’URI cible avec un / de fin. Par exemple, de https://<hostname>/StaticFiles à https://<hostname>/StaticFiles/. Les URL relatives au sein du répertoire StaticFiles ne sont pas valides sans barre oblique de fin (/).

FileExtensionContentTypeProvider

La classe FileExtensionContentTypeProvider contient une propriété Mappings qui agit comme un mappage des extensions de fichiers à des types de contenu MIME. Dans l’exemple suivant, plusieurs extensions de fichiers sont mappées à des types MIME connus. L’extension .rtf est remplacée et l’extension .mp4 est supprimée :

// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages"
});

Le code suivant montre Startup.Configure en utilisant le code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.AspNetCore.StaticFiles;
    // using Microsoft.Extensions.FileProviders;
    // using System.IO;

    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Consultez Types de contenu MIME.

Types de contenu non standard

L’intergiciel de fichiers statiques comprend près de 400 types de contenu de fichier. Si l’utilisateur demande un fichier d’un type inconnu, l’intergiciel de fichiers statiques transmet la demande à l’intergiciel suivant dans le pipeline. Si aucun intergiciel ne gère la requête, une réponse 404 introuvable est retournée. Si l’exploration des répertoires est activée, un lien vers le fichier est affiché dans la liste de répertoires.

Le code suivant permet de délivrer des types inconnus et rend le fichier inconnu en tant qu’image :

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

Le code suivant montre Startup.Configure associé au code précédent :

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

Avec le code précédent, une requête pour un fichier avec un type de contenu inconnu est retournée en tant qu’image.

Avertissement

L’activation de ServeUnknownFileTypes pose un problème de sécurité. Il est désactivé par défaut et son utilisation est déconseillée. FileExtensionContentTypeProvider fournit une alternative plus sûre pour délivrer des fichiers avec des extensions non standard.

Délivrer des fichiers à partir de plusieurs emplacements

UseStaticFiles et UseFileServer correspondent par défaut au fournisseur de fichiers pointant sur wwwroot. Des instances supplémentaires de UseStaticFiles et UseFileServer peuvent être fournies avec d’autres fournisseurs de fichiers pour délivrer des fichiers à partir d’autres emplacements. Pour plus d’informations, consultez ce problème GitHub.

Considérations de sécurité pour les fichiers statiques

Avertissement

UseDirectoryBrowser et UseStaticFiles peuvent entraîner une fuite de secrets. La désactivation de l’exploration de répertoires est fortement recommandée en production. Examinez attentivement les répertoires qui sont activés via UseStaticFiles ou UseDirectoryBrowser. L’ensemble du répertoire et de ses sous-répertoires deviennent accessibles publiquement. Stockez les fichiers qui peuvent être délivrés au public dans un répertoire dédié, comme <content_root>/wwwroot. Séparez ces fichiers des vues MVC, de Razor Pages, des fichiers de configuration, etc.

  • Les URL pour le contenu exposé avec UseDirectoryBrowser et UseStaticFiles sont soumises aux restrictions de respect de la casse et de caractères du système de fichiers sous-jacent. Par exemple, Windows est insensible à la casse, mais macOS et Linux ne le sont pas.

  • Les applications ASP.NET Core hébergées dans IIS utilisent le module ASP.NET Core pour transférer toutes les requêtes à l’application, notamment les requêtes de fichiers statiques. Le gestionnaire de fichiers statiques IIS n’est pas utilisé et n’a aucune chance de gérer les demandes.

  • Effectuez les étapes suivantes dans le Gestionnaire des services Internet (IIS) pour supprimer le gestionnaire de fichiers statiques d’IIS au niveau du serveur ou du site web :

    1. Accédez à la fonctionnalité Modules.
    2. Sélectionnez StaticFileModule dans la liste.
    3. Cliquez sur Supprimer dans l’encadré Actions.

Avertissement

Si le gestionnaire de fichiers statiques d’IIS est activé et que le module ASP.NET Core est incorrectement configuré, les fichiers statiques peuvent être délivrés. Cela se produit par exemple si le fichier web.config n’est pas déployé.

  • Placez les fichiers de code, y compris .cs et .cshtml, en dehors de la racine web du projet d’application. Par conséquent, une séparation logique est créée entre le contenu côté client et le code basé sur le serveur de l’application. Ceci empêche la fuite de code côté serveur.

Ressources supplémentaires