Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Note
This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 9 version of this article.
Static files, also called static assets, are files an ASP.NET Core app that aren't dynamically generated. Instead, they're served directly to clients on request, such as HTML, CSS, image, and JavaScript files.
For Blazor static files guidance, which adds to or supersedes the guidance in this article, see ASP.NET Core Blazor static files.
To enable static file handling in ASP.NET Core, call MapStaticAssets.
By default, static files are stored within the project's web root directory. The default directory is {CONTENT ROOT}/wwwroot, where the {CONTENT ROOT} placeholder is the app's content root. Only files in the wwwroot folder will be addressable, so you don't need to worry about the rest of your code.
Only files with specific file extensions mapped to supported media types are treated as static web assets.
Static web assets are discovered at build time and optimized using content-based fingerprinting to prevent the reuse of old files. Assets are also compressed to reduce asset delivery time.
At runtime, the discovered static web assets are exposed as endpoints with HTTP headers applied, such as caching headers and content type headers. An asset is served once until the file changes or the browser clears its cache. The ETag, Last-Modified, and Content-Type headers are set. The browser is prevented from using stale assets after an app is updated.
Delivery of static assets is based on endpoint routing, so it works with other endpoint-aware features, such as authorization. It's designed to work with all UI frameworks, including Blazor, Razor Pages, and MVC.
Map Static Assets provides the following benefits:
- Build-time compression for all the assets in the app, including JavaScript (JS) and stylesheets but excluding image and font assets that are already compressed. Gzip (
Content-Encoding: gz) compression is used during development. Gzip and Brotli (Content-Encoding: br) compression are both used during publish. - Fingerprinting for all assets at build time with a Base64-encoded string of the SHA-256 hash of each file's content. This prevents reusing an old version of a file, even if the old file is cached. Fingerprinted assets are cached using the
immutabledirective, which results in the browser never requesting the asset again until it changes. For browsers that don't support theimmutabledirective, amax-agedirective is added.- Even if an asset isn't fingerprinted, content based
ETagsare generated for each static asset using the fingerprint hash of the file as theETagvalue. This ensures that the browser only downloads a file if its content changes (or the file is being downloaded for the first time). - Internally, the framework maps physical assets to their fingerprints, which allows the app to:
- Find automatically-generated assets, such as Razor component scoped CSS for Blazor's CSS isolation feature and JS assets described by JS import maps.
- Generate link tags in the
<head>content of the page to preload assets.
- Even if an asset isn't fingerprinted, content based
Map Static Assets doesn't provide features for minification or other file transformations. Minification is usually handled by custom code or third-party tooling.
To enable static file handling in ASP.NET Core, call UseStaticFiles.
By default, static files are stored within the project's web root directory. The default directory is {CONTENT ROOT}/wwwroot, where the {CONTENT ROOT} placeholder is the app's content root. Only files in the wwwroot folder will be addressable, so you don't need to worry about the rest of your code.
At runtime, static web assets are returned by Static File Middleware when requested with asset modification and content type headers applied. The ETag, Last-Modified, and Content-Type headers are set.
Static File Middleware enables static file serving and is used by an app when UseStaticFiles is called in the app's request processing pipeline. Files are served from the path specified in IWebHostEnvironment.WebRootPath or WebRootFileProvider, which defaults to the web root folder, typically wwwroot.
You can also serve static web assets from referenced projects and packages.
Change the web root directory
Use the UseWebRoot method if you want to change the web root. For more information, see ASP.NET Core fundamentals overview.
Prevent publishing files in wwwroot with the <Content> project item in the project file. The following example prevents publishing content in wwwroot/local and its sub-directories:
<ItemGroup>
<Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>
The CreateBuilder method sets the content root to the current directory:
var builder = WebApplication.CreateBuilder(args);
The CreateDefaultBuilder method sets the content root to the current directory:
Host.CreateDefaultBuilder(args)
In the request processing pipeline after the call to UseHttpsRedirection, call MapStaticAssets in the app's request processing pipeline to enable serving static files from the app's web root:
app.MapStaticAssets();
In the request processing pipeline after the call to UseHttpsRedirection, call UseStaticFiles in the app's request processing pipeline to enable serving static files from the app's web root:
app.UseStaticFiles();
Static files are accessible via a path relative to the web root.
To access an image at wwwroot/images/favicon.png:
- URL format:
https://{HOST}/images/{FILE NAME}- The
{HOST}placeholder is the host. - The
{FILE NAME}placeholder is the file name.
- The
- Examples
- Absolute URL:
https://localhost:5001/images/favicon.png - Root relative URL:
images/favicon.png
- Absolute URL:
In a Blazor app, images/favicon.png loads the icon image (favicon.png) from the app's wwwroot/images folder:
<link rel="icon" type="image/png" href="images/favicon.png" />
In Razor Pages and MVC apps, the tilde character ~ points to the web root. In the following example, ~/images/favicon.png loads the icon image (favicon.png) from the app's wwwroot/images folder:
<link rel="icon" type="image/png" href="~/images/favicon.png" />
Short-circuit the middleware pipeline
To avoid running the entire middleware pipeline after a static asset is matched, which is the behavior of UseStaticFiles, call ShortCircuit on MapStaticAssets. Calling ShortCircuit immediately executes the endpoint and returns the response, preventing other middleware from executing for static asset requests:
app.MapStaticAssets().ShortCircuit();
Control static file caching during development
When running in the Development environment, for example during Visual Studio Hot Reload development testing, the framework overrides cache headers to prevent browsers from caching static files. This helps ensure that the latest version of files are used when files change, avoiding issues with stale content. In production, the correct cache headers are set, allowing browsers to cache static assets as expected.
To disable this behavior, set EnableStaticAssetsDevelopmentCaching to true in the Development environment's app setting file (appsettings.Development.json).
Static files in non-Development environments
When running an app locally, static web assets are only enabled in the Development environment. To enable static files for environments other than Development during local development and testing (for example, in the Staging environment), call UseStaticWebAssets on the WebApplicationBuilder.
Warning
Call UseStaticWebAssets for the exact environment to prevent activating the feature in production, as it serves files from separate locations on disk other than from the project. The example in this section checks for the Staging environment with IsStaging.
if (builder.Environment.IsStaging())
{
builder.WebHost.UseStaticWebAssets();
}
Serve files outside of the web root directory via IWebHostEnvironment.WebRootPath
When IWebHostEnvironment.WebRootPath is set to a folder other than wwwroot, the following default behaviors are exhibited:
- In the development environment, static assets are served from
wwwrootif assets with the same name are in bothwwwrootand a different folder assigned to WebRootPath. - In any environment other than development, duplicate static assets are served from the WebRootPath folder.
Consider a web app created from the empty web template:
- Containing an
Index.htmlfile inwwwrootandwwwroot-custom. - The
Programfile is updated to setWebRootPath = "wwwroot-custom".
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
WebRootPath = "wwwroot-custom"
});
By default, for requests to /:
- In the development environment,
wwwroot/Index.htmlis returned. - In any environment other than development,
wwwroot-custom/Index.htmlis returned.
To ensure assets from wwwroot-custom are always returned, use one of the following approaches:
Delete duplicate-named assets in
wwwroot.Set
ASPNETCORE_ENVIRONMENTinProperties/launchSettings.jsonto any value other thanDevelopment.Disable static web assets by setting
<StaticWebAssetsEnabled>tofalsein the app's project file. WARNING: Disabling static web assets disables Razor class libraries.Add the following XML to the project file:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
The following code updates WebRootPath to a non-Development value (Staging), guaranteeing duplicate content is returned from wwwroot-custom rather than wwwroot:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
Static File Middleware
Static File Middleware enables static file serving in specific static files scenarios, usually in addition to Map Static Assets endpoint routing conventions (MapStaticAssets).
Static File Middleware is included in request processing when UseStaticFiles is called in the app's request processing pipeline, typically after Map Static Assets endpoint conventions (MapStaticAssets) are added.
Map Static Assets endpoint conventions are used in apps that target .NET 9 or later. Static File Middleware must be used in apps that target versions of .NET prior to .NET 9.
Static File Middleware serves static files, but it doesn't provide the same level of optimization as Map Static Assets endpoint conventions. The build-time compression and fingerprinting features of Map Static Assets endpoint conventions aren't available when only relying on Static File Middleware.
The endpoint conventions are optimized for serving assets that the app has knowledge of at runtime. If the app serves assets from other locations, such as disk or embedded resources, Static File Middleware should be used.
The following features covered in this article are supported with Static File Middleware but not with Map Static Assets endpoint conventions:
- Serve files outside of the web root directory
- Set HTTP response headers
- Serving files from disk or embedded resources, or other locations
- Directory browsing
- Serve default documents
- Combine static files, default documents, and directory browsing
- Map file extensions to MIME types
- Serving non-standard content types
Serve files outside of the web root directory via UseStaticFiles
Consider the following directory hierarchy with static files residing outside of the app's web root in a folder named ExtraStaticFiles:
wwwrootcssimagesjs
ExtraStaticFilesimagesred-rose.jpg
A request can access red-rose.jpg by configuring a new instance of Static File Middleware:
Namespaces for the following API:
using Microsoft.Extensions.FileProviders;
In the request processing pipeline after the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files"
});
In the preceding code, the ExtraStaticFiles directory hierarchy is exposed publicly via the static-files URL segment. A request to https://{HOST}/StaticFiles/images/red-rose.jpg, where the {HOST} placeholder is the host, serves the red-rose.jpg file.
The following markup references ExtraStaticFiles/images/red-rose.jpg:
<img src="static-files/images/red-rose.jpg" alt="A red rose" />
For the preceding example, tilde-slash notation is supported in Razor Pages and MVC views (src="~/StaticFiles/images/red-rose.jpg"), not for Razor components in Blazor apps.
Serve files from multiple locations
The guidance in this section applies to Razor Pages and MVC apps. For guidance that applies to Blazor Web Apps, see ASP.NET Core Blazor static files.
Consider the following markup that displays a company logo:
<img src="~/logo.png" asp-append-version="true" alt="Company logo">
The developer intends to use the Image Tag Helper to append a version and serve the file from a custom location, a folder named ExtraStaticFiles.
The following example calls MapStaticAssets to serve files from wwwroot and UseStaticFiles to serve files from ExtraStaticFiles:
In the request processing pipeline after the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});
The following example calls UseStaticFiles twice to serve files from both wwwroot and ExtraStaticFiles.
In the request processing pipeline after the existing call to UseStaticFiles:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});
Using the preceding code, the ExtraStaticFiles/logo.png file is displayed. However, the Image Tag Helper (AppendVersion) isn't applied because the Tag Helper depends on WebRootFileProvider, which hasn't been updated to include the ExtraStaticFiles folder.
The following code updates the WebRootFileProvider to include the ExtraStaticFiles folder by using a CompositeFileProvider. This enables the Image Tag Helper to apply a version to images in the ExtraStaticFiles folder.
Namespace for the following API:
using Microsoft.Extensions.FileProviders;
In the request processing pipeline before the existing call to MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider, newPathProvider);
app.Environment.WebRootFileProvider = compositeProvider;
UseStaticFiles and UseFileServer default to the file provider pointing at wwwroot. Additional instances of UseStaticFiles and UseFileServer can be provided with other file providers to serve files from other locations. For more information, see UseStaticFiles still needed with UseFileServer for wwwroot (dotnet/AspNetCore.Docs #15578).
Set HTTP response headers
Use StaticFileOptions to set HTTP response headers. In addition to configuring Static File Middleware to serve static files, the following code sets the Cache-Control header to 604,800 seconds (one week).
Namespaces for the following API:
using Microsoft.AspNetCore.Http;
In the request processing pipeline after the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", "public, max-age=604800");
}
});
Large collection of assets
When dealing with large collections of assets, which is considered to be around 1,000 or more assets, we recommend using a bundler to reduce the final number of assets served by the app or to combine MapStaticAssets with UseStaticFiles.
MapStaticAssets eagerly loads the precomputed metadata captured during the build process for the resources in order to support compression, caching, and fingerprinting. These features come at the cost of greater memory usage by the app. For assets that are frequently accessed, it's usually worth the costs. For assets that aren't frequently accessed, the trade-off might not be worth the costs.
If you don't use bundling, we recommend that you combine MapStaticAssets with UseStaticFiles. The following example demonstrates the approach.
In the project file (.csproj), the StaticWebAssetEndpointExclusionPattern MSBuild property is used to filter endpoints from the final manifest for MapStaticAssets. Excluded files are served by UseStaticFiles and don't benefit from compression, caching, and fingerprinting.
When setting the value of StaticWebAssetEndpointExclusionPattern, retain $(StaticWebAssetEndpointExclusionPattern) to keep the framework's default exclusion pattern. Add additional patterns in a semicolon-separated list.
In the following example, the exclusion patten adds the static files in the lib/icons folder, which represents a hypothetical batch of icons:
<StaticWebAssetEndpointExclusionPattern>
$(StaticWebAssetEndpointExclusionPattern);lib/icons/**
</StaticWebAssetEndpointExclusionPattern>
After HTTPS Redirection Middleware (app.UseHttpsRedirection();) processing in the Program file:
- Call UseStaticFiles to handle the excluded files (
lib/icons/**) and any other files not covered by MapStaticAssets. - Call MapStaticAssets after UseStaticFiles to handle critical application files (CSS, JS, images).
app.UseStaticFiles();
app.UseAuthorization();
app.MapStaticAssets();
Static file authorization
When an app adopts a fallback authorization policy, authorization is required for all requests that don't explicitly specify an authorization policy, including requests for static files after Authorization Middleware processes requests. Allow anonymous access to static files by applying AllowAnonymousAttribute to the endpoint builder for static files:
app.MapStaticAssets().Add(endpointBuilder =>
endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()));
When an app adopts a fallback authorization policy, authorization is required for all requests that don't explicitly specify an authorization policy, including requests for static files after Authorization Middleware processes requests. The ASP.NET Core templates allow anonymous access to static files by calling UseStaticFiles before calling UseAuthorization. Most apps follow this pattern. When the Static File Middleware is called before the authorization middleware:
- No authorization checks are performed on the static files.
- Static files served by the Static File Middleware, such as those web root (typically,
wwwroot), are publicly accessible.
To serve static files based on authorization:
- Confirm that the app sets the fallback authorization policy to require authenticated users.
- Store the static file outside of the app's web root.
- After calling UseAuthorization, call UseStaticFiles, specifying the path to the static files folder outside of the web root.
Namespaces for the following API:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;
Service registration:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
In the request processing pipeline after the call to UseAuthorization:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "SecureStaticFiles")),
RequestPath = "/static-files"
});
Namespaces for the following API:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;
In Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
In Startup.Configure after the call to UseAuthorization:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "SecureStaticFiles")),
RequestPath = "/static-files"
});
In the preceding code, the fallback authorization policy requires authenticated users. Endpoints, such as controllers and Razor Pages, that specify their own authorization requirements don't use the fallback authorization policy. For example, Razor Pages, controllers, or action methods with [AllowAnonymous] or [Authorize(PolicyName="MyPolicy")] use the applied authorization attribute rather than the fallback authorization policy.
RequireAuthenticatedUser adds DenyAnonymousAuthorizationRequirement to the current instance, which enforces that the current user is authenticated.
Static assets stored in the app's web root are publicly accessible because the default Static File Middleware (UseStaticFiles) is called before UseAuthorization. Static assets in the SecureStaticFiles folder require authentication.
An alternative approach to serve files based on authorization is to:
- Store the files outside of the web root and any directory accessible to Static File Middleware.
- Serve the files via an action method to which authorization is applied and return a FileResult object.
From a Razor page (Pages/BannerImage.cshtml.cs):
public class BannerImageModel : PageModel
{
private readonly IWebHostEnvironment _env;
public BannerImageModel(IWebHostEnvironment env) => _env = env;
public PhysicalFileResult OnGet()
{
var filePath = Path.Combine(
_env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
}
From a controller (Controllers/HomeController.cs):
[Authorize]
public IActionResult BannerImage()
{
var filePath = Path.Combine(
_env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
The preceding approach requires a page or endpoint per file.
The following route endpoint example returns files for authenticated users.
In the Program file:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});
...
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileName);
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
The following route endpoint example uploads files for authenticated users in the administrator role ("admin").
In the Program file:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});
...
// IFormFile uses memory buffer for uploading. For handling large
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://free.blessedness.top/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker,
HttpContext context) =>
{
// Don't rely on the value in 'file.FileName', as it's only metadata that can
// be manipulated by the end-user. Consider 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");
In Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});
In Startup.Configure:
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileName);
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
The following code uploads files for authenticated users in the administrator role ("admin").
In Startup.ConfigureServices:
services.AddAuthorization(options =>
{
options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});
In Startup.Configure:
// IFormFile uses memory buffer for uploading. For handling large
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://free.blessedness.top/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker,
HttpContext context) =>
{
// Don't rely on the value in 'file.FileName', as it's only metadata that can
// be manipulated by the end-user. Consider 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");
Directory browsing
Directory browsing allows directory listing within specified directories.
Directory browsing is disabled by default for security reasons. For more information, see Security considerations for static files.
Enable directory browsing with the following API:
In the following example:
- An
imagesfolder at the root of the app holds images for directory browsing. - The request path to browse the images is
/DirectoryImages. - Calling UseStaticFiles and setting the FileProvider of StaticFileOptions enables displaying browser links to the individual files.
Namespaces for the following API:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
Service registration:
builder.Services.AddDirectoryBrowser();
In the request processing pipeline after the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
var fileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/DirectoryImages";
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
Namespaces for the following API:
using Microsoft.Extensions.FileProviders;
using System.IO;
In Startup.ConfigureServices:
services.AddDirectoryBrowser();
In Startup.Configure after the existing call to UseStaticFiles:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/DirectoryImages"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/DirectoryImages"
});
The preceding code allows directory browsing of the wwwroot/images folder using the URL https://{HOST}/DirectoryImages with links to each file and folder, where the {HOST} placeholder is the host.
AddDirectoryBrowser adds services required by the Directory Browsing Middleware, including HtmlEncoder. These services may be added by other calls, such as AddRazorPages, but we recommend calling AddDirectoryBrowser to ensure the services are added.
Serve default documents
Setting a default page provides visitors a starting point on a site. To serve a default file from wwwroot without requiring the request URL to include the file's name, call the UseDefaultFiles method.
UseDefaultFiles is a URL rewriter that doesn't serve the file. In the request processing pipeline before the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier):
app.UseDefaultFiles();
With UseDefaultFiles, requests to a folder in wwwroot search for:
default.htmdefault.htmlindex.htmindex.html
The first file found from the list is served as though the request included the file's name. The browser URL continues to reflect the URI requested.
The following code changes the default file name to default-document.html:
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("default-document.html");
app.UseDefaultFiles(options);
Combine static files, default documents, and directory browsing
UseFileServer combines the functionality of UseStaticFiles, UseDefaultFiles, and optionally UseDirectoryBrowser.
In the request processing pipeline after the existing call to either MapStaticAssets (.NET 9 or later) or UseStaticFiles (.NET 8 or earlier), call UseFileServer to enable the serving of static files and the default file:
app.UseFileServer();
Directory browsing isn't enabled for the preceding example.
The following code enables the serving of static files, the default file, and directory browsing.
Service registration:
builder.Services.AddDirectoryBrowser();
In the request processing pipeline after the existing call to UseStaticFiles:
app.UseFileServer(enableDirectoryBrowsing: true);
In Startup.ConfigureServices:
services.AddDirectoryBrowser();
In Startup.Configure after the existing call to UseStaticFiles:
app.UseFileServer(enableDirectoryBrowsing: true);
For the host address (/), UseFileServer returns the default HTML document before the default Razor Page (Pages/Index.cshtml) or default MVC view (Home/Index.cshtml).
Consider the following directory hierarchy:
wwwrootcssimagesjs
ExtraStaticFilesimageslogo.png
default.html
The following code enables the serving of static files, the default file, and directory browsing of ExtraStaticFiles.
Namespaces for the following API:
using Microsoft.Extensions.FileProviders;
Service registration:
builder.Services.AddDirectoryBrowser();
In the request processing pipeline after the existing call to UseStaticFiles:
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files",
EnableDirectoryBrowsing = true
});
Namespaces for the following API:
using Microsoft.Extensions.FileProviders;
using System.IO;
In Startup.ConfigureServices:
services.AddDirectoryBrowser();
In Startup.Configure after the existing call to UseStaticFiles:
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files",
EnableDirectoryBrowsing = true
});
AddDirectoryBrowser must be called when the EnableDirectoryBrowsing property value is true.
Using the preceding file hierarchy and code, URLs resolve as shown in the following table (the {HOST} placeholder is the host).
| URI | Response file |
|---|---|
https://{HOST}/static-files/images/logo.png |
ExtraStaticFiles/images/logo.png |
https://{HOST}/static-files |
ExtraStaticFiles/default.html |
If no default-named file exists in the ExtraStaticFiles directory, https://{HOST}/static-files returns the directory listing with clickable links, where the {HOST} placeholder is the host.
UseDefaultFiles and UseDirectoryBrowser perform a client-side redirect from the target URI without a trailing / to the target URI with a trailing /. For example, from https://{HOST}/static-files (no trailing /) to https://{HOST}/static-files/ (includes a trailing /). Relative URLs within the ExtraStaticFiles directory are invalid without a trailing slash (/) unless the RedirectToAppendTrailingSlash option of DefaultFilesOptions is used.
Map file extensions to MIME types
Note
For guidance that applies to Blazor apps, see ASP.NET Core Blazor static files.
Use FileExtensionContentTypeProvider.Mappings to add or modify file extension to MIME content type mappings. In the following example, several file extensions are mapped to known MIME types. The .rtf extension is replaced, and .mp4 is removed:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
...
// 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
});
When you have several static file options to configure, you can alternatively set the provider using StaticFileOptions:
var provider = new FileExtensionContentTypeProvider();
...
builder.Services.Configure<StaticFileOptions>(options =>
{
options.ContentTypeProvider = provider;
});
app.UseStaticFiles();
In Startup.Configure:
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 = "/images",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/images"
});
For more information, see MIME content types.
Non-standard content types
The Static File Middleware understands almost 400 known file content types. If the user requests a file with an unknown file type, the Static File Middleware passes the request to the next middleware in the pipeline. If no middleware handles the request, a 404 Not Found response is returned. If directory browsing is enabled, a link to the file is displayed in a directory listing.
The following code enables serving unknown content types and renders the unknown file as an image:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
With the preceding code, a request for a file with an unknown content type is returned as an image.
Warning
Enabling ServeUnknownFileTypes is a security risk. It's disabled by default, and its use is discouraged. Map file extensions to MIME types provides a safer alternative to serving files with non-standard extensions.
Provide a custom static files manifest
If staticAssetsManifestPath is null, the IHostEnvironment.ApplicationName is used to locate the manifest. Alternatively, specify a full path to the manifest file. If a relative path is used, the framework searches for the file in the AppContext.BaseDirectory.
Security considerations for static files
Warning
UseDirectoryBrowser and UseStaticFiles can leak secrets. Disabling directory browsing in production is highly recommended. Carefully review which directories are enabled via UseStaticFiles or UseDirectoryBrowser. The entire directory and its sub-directories become publicly accessible. Store files suitable for serving to the public in a dedicated directory, such as <content_root>/wwwroot. Separate these files from MVC views, Razor Pages, configuration files, etc.
The URLs for content exposed with UseDirectoryBrowser and UseStaticFiles are subject to the case sensitivity and character restrictions of the underlying file system. For example, Windows is case insensitive, but macOS and Linux aren't.
ASP.NET Core apps hosted in IIS use the ASP.NET Core Module to forward all requests to the app, including static file requests. The IIS static file handler isn't used and has no chance to handle requests.
Complete the following steps in IIS Manager to remove the IIS static file handler at the server or website level:
- Navigate to the Modules feature.
- Select StaticFileModule in the list.
- Click Remove in the Actions sidebar.
Warning
If the IIS static file handler is enabled and the ASP.NET Core Module is configured incorrectly, static files are served. This happens, for example, if the web.config file isn't deployed.
- Place code files, including
.csand.cshtml, outside of the app project's web root. A logical separation is therefore created between the app's client-side content and server-based code. This prevents server-side code from being leaked.
MSBuild properties
The following tables show the static files MSBuild properties and metadata descriptions.
| Property | Description |
|---|---|
EnableDefaultCompressedItems |
Enables default compression include/exclude patterns. |
CompressionIncludePatterns |
Semicolon-separated list of file patterns to include for compression. |
CompressionExcludePatterns |
Semicolon-separated list of file patterns to exclude from compression. |
EnableDefaultCompressionFormats |
Enables default compression formats (Gzip and Brotli). |
BuildCompressionFormats |
Compression formats to use during build. |
PublishCompressionFormats |
Compression formats to use during publish. |
DisableBuildCompression |
Disables compression during build. |
CompressDiscoveredAssetsDuringBuild |
Compresses discovered assets during build. |
BrotliCompressionLevel |
Compression level for the Brotli algorithm. |
StaticWebAssetBuildCompressAllAssets |
Compresses all assets during build, not just assets discovered or computed during a build. |
StaticWebAssetPublishCompressAllAssets |
Compresses all assets during publish, not just assets discovered or computed during a build. |
| Property | Description |
|---|---|
StaticWebAssetBasePath |
Base URL path for all the assets in a library. |
StaticWebAssetsFingerprintContent |
Enables content fingerprinting for cache busting. |
StaticWebAssetFingerprintingEnabled |
Enables fingerprinting feature for static web assets. |
StaticWebAssetsCacheDefineStaticWebAssetsEnabled |
Enables caching for static web asset definitions. |
StaticWebAssetEndpointExclusionPattern |
Pattern for excluding endpoints. |
| Item group | Description | Metadata |
|---|---|---|
StaticWebAssetContentTypeMapping |
Maps file patterns to content types and cache headers for endpoints. | Pattern, Cache |
StaticWebAssetFingerprintPattern |
Defines patterns for applying fingerprints to static web assets for cache busting. | Pattern, Expression |
Metadata Descriptions:
Pattern: A glob pattern used to match files. ForStaticWebAssetContentTypeMapping, it matches files to determine their content type (for example,*.jsfor JavaScript files). ForStaticWebAssetFingerprintPattern, it identifies multi-extension files that require special fingerprinting treatment (for example,*.lib.module.js).Cache: Specifies theCache-Controlheader value for the matched content type. This controls browser caching behavior (for example,max-age=3600, must-revalidatefor media files).Expression: Defines how the fingerprint is inserted into the filename. The default is#[.{FINGERPRINT}], which inserts the fingerprint ({FINGERPRINT}placeholder) before the extension.
The following example maps the bitmap file pattern (.bmp) to the image/bmp content type with the {CACHE HEADER} placeholder representing the Cache-Control header to use for non-fingerprinted endpoints:
<ItemGroup>
<StaticWebAssetContentTypeMapping Include="image/bmp" Cache="{CACHE HEADER}" Pattern="*.bmp" />
</ItemGroup>
Runtime configuration options
The following table describes the runtime configuration options.
| Configuration key | Description |
|---|---|
ReloadStaticAssetsAtRuntime |
Enables dev-time hot reloading of static assets: serves modified web root (wwwroot) files (recomputes ETag, recompresses if required) instead of build-time manifest versions. Defaults to enabled only when serving a build manifest unless explicitly set. |
DisableStaticAssetNotFoundRuntimeFallback |
When true, suppresses the fallback endpoint that serves newly added files not present in the build manifest. When false or absent, a file-exists-checked {**path} fallback (GET/HEAD) logs a warning and serves the file with a computed ETag. |
EnableStaticAssetsDevelopmentCaching |
When true, preserves the original Cache-Control headers on asset descriptors. When false or absent, rewrites Cache-Control headers to no-cache to avoid aggressive client caching during development. |
EnableStaticAssetsDevelopmentIntegrity |
When true, keeps integrity properties on asset descriptors. When false or absent, removes any integrity property to prevent mismatches when files change during development. |
Additional resources
ASP.NET Core