title | author | description | monikerRange | ms.author | ms.custom | ms.date | uid |
---|---|---|---|---|---|---|---|
Static files in ASP.NET Core |
rick-anderson |
Learn how to serve and secure static files and configure static file hosting middleware behaviors in an ASP.NET Core web app. |
>= aspnetcore-3.1 |
riande |
mvc |
7/25/2024 |
fundamentals/static-files |
:::moniker range=">= aspnetcore-9.0"
Static files, such as HTML, CSS, images, and JavaScript, are assets an ASP.NET Core app serves directly to clients by default.
For Blazor static files guidance, which adds to or supersedes the guidance in this article, see xref:blazor/fundamentals/static-files.
Static files are stored within the project's web root directory. The default directory is {content root}/wwwroot
, but it can be changed with the xref:Microsoft.AspNetCore.Hosting.HostingAbstractionsWebHostBuilderExtensions.UseWebRoot%2A method. For more information, see Content root and Web root.
The xref:Microsoft.AspNetCore.Builder.WebApplication.CreateBuilder%2A method sets the content root to the current directory:
Static files are accessible via a path relative to the web root. For example, the Web Application project templates contain several folders within the wwwroot
folder:
wwwroot
css
js
lib
Consider an app with the wwwroot/images/MyImage.jpg
file. The URI format to access a file in the images
folder is https://<hostname>/images/<image_file_name>
. For example, https://localhost:5001/images/MyImage.jpg
Creating performant web apps requires optimizing asset delivery to the browser. Possible optimizations include:
- Serve a given asset once until the file changes or the browser clears its cache. Set the ETag header.
- Prevent the browser from using old or stale assets after an app is updated. Set the Last-Modified header.
- Set up proper caching headers.
- Use caching middleware.
- Serve compressed versions of the assets when possible.
- Use a CDN to serve the assets closer to the user.
- Minimize the size of assets served to the browser. This optimization doesn't include minification.
xref:Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssets%2A are routing endpoint conventions that optimize the delivery of static assets in an app. It's designed to work with all UI frameworks, including Blazor, Razor Pages, and MVC.
UseStaticFiles
also serves static files, but it doesn't provide the same level of optimization as MapStaticAssets
. For a comparison of UseStaticFiles
and MapStaticAssets
, see Optimizing static web asset delivery
.
The default web app templates call the xref:Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssets%2A method in Program.cs
, which enables static files to be served:
The parameterless UseStaticFiles
method overload marks the files in web root as servable. The following markup references wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
In the preceding markup, the tilde character ~
points to the web root.
Consider a directory hierarchy in which the static files to be served reside outside of the web root:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
A request can access the red-rose.jpg
file by configuring the Static File Middleware as follows:
In the preceding code, the MyStaticFiles directory hierarchy is exposed publicly via the StaticFiles URI segment. A request to https://<hostname>/StaticFiles/images/red-rose.jpg
serves the red-rose.jpg
file.
The following markup references MyStaticFiles/images/red-rose.jpg
:
To serve files from multiple locations, see Serve files from multiple locations.
A xref:Microsoft.AspNetCore.Builder.StaticFileOptions object can be used to set HTTP response headers. In addition to configuring static file serving from the web root, the following code sets the Cache-Control header:
The preceding code makes static files publicly available in the local cache for one week.
The ASP.NET Core templates call xref:Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssets%2A before calling xref:Microsoft.AspNetCore.Builder.AuthorizationAppBuilderExtensions.UseAuthorization%2A. 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 under
wwwroot
, are publicly accessible.
To serve static files based on authorization:
- Store them outside of
wwwroot
. - Call
UseStaticFiles
, specifying a path, after callingUseAuthorization
. - Set the fallback authorization policy.
In the preceding code, the fallback authorization policy requires all users to be authenticated. Endpoints such as controllers, Razor Pages, etc 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.
xref:Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder.RequireAuthenticatedUser%2A adds xref:Microsoft.AspNetCore.Authorization.Infrastructure.DenyAnonymousAuthorizationRequirement to the current instance, which enforces that the current user is authenticated.
Static assets under wwwroot
are publicly accessible because the default Static File Middleware (app.UseStaticFiles();
) is called before UseAuthentication
. Static assets in the MyStaticFiles folder require authentication. The sample code demonstrates this.
An alternative approach to serve files based on authorization is to:
-
Store them outside of
wwwroot
and any directory accessible to the Static File Middleware. -
Serve them via an action method to which authorization is applied and return a xref:Microsoft.AspNetCore.Mvc.FileResult object:
The preceding approach requires a page or endpoint per file. The following code returns files or uploads files for authenticated users:
:::code language="csharp" source="~/fundamentals/static-files/samples/9.x/StaticFileAuth/Program.cs" id="snippet_1":::
IFormFile in the preceding sample uses memory buffer for uploading. For handling large file use streaming. See Upload large files with streaming.
See the StaticFileAuth GitHub folder for the complete sample.
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 xref:Microsoft.Extensions.DependencyInjection.DirectoryBrowserServiceExtensions.AddDirectoryBrowser%2A and xref:Microsoft.AspNetCore.Builder.DirectoryBrowserExtensions.UseDirectoryBrowser%2A:
The preceding code allows directory browsing of the wwwroot/images folder using the URL https://<hostname>/MyImages
, with links to each file and folder:
AddDirectoryBrowser
adds services required by the directory browsing middleware, including xref:System.Text.Encodings.Web.HtmlEncoder. These services may be added by other calls, such as xref:Microsoft.Extensions.DependencyInjection.MvcServiceCollectionExtensions.AddRazorPages%2A, but we recommend calling AddDirectoryBrowser
to ensure the services are added in all apps.
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 xref:Microsoft.AspNetCore.Builder.DefaultFilesExtensions.UseDefaultFiles%2A method:
UseDefaultFiles
must be called before UseStaticFiles
to serve the default file. UseDefaultFiles
is a URL rewriter that doesn't serve the file.
With UseDefaultFiles
, requests to a folder in wwwroot
search for:
default.htm
default.html
index.htm
index.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. For example, in the sample app, a request to https://localhost:<port>/def/
serves default.html
from wwwroot/def
.
The following code changes the default file name to mydefault.html
:
xref:Microsoft.AspNetCore.Builder.FileServerExtensions.UseFileServer* combines the functionality of UseStaticFiles
, UseDefaultFiles
, and optionally UseDirectoryBrowser
.
Call app.UseFileServer
to enable the serving of static files and the default file. Directory browsing isn't enabled:
The following code enables the serving of static files, the default file, and directory browsing:
Consider the following directory hierarchy:
wwwroot
css
images
js
MyStaticFiles
defaultFiles
default.html
image3.png
images
MyImage.jpg
The following code enables the serving of static files, the default file, and directory browsing of MyStaticFiles
:
xref:Microsoft.Extensions.DependencyInjection.DirectoryBrowserServiceExtensions.AddDirectoryBrowser%2A must be called when the EnableDirectoryBrowsing
property value is true
.
Using the preceding file hierarchy and code, URLs resolve as follows:
URI | Response |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
directory listing |
https://<hostname>/StaticFiles/defaultFiles |
MyStaticFiles/defaultFiles/default.html |
https://<hostname>/StaticFiles/defaultFiles/image3.png |
MyStaticFiles/defaultFiles//image3.png |
If no default-named file exists in the MyStaticFiles directory, https://<hostname>/StaticFiles
returns the directory listing with clickable links:
xref:Microsoft.AspNetCore.Builder.DefaultFilesExtensions.UseDefaultFiles* and xref:Microsoft.AspNetCore.Builder.DirectoryBrowserExtensions.UseDirectoryBrowser* perform a client-side redirect from the target URI without a trailing /
to the target URI with a trailing /
. For example, from https://<hostname>/StaticFiles
to https://<hostname>/StaticFiles/
. Relative URLs within the StaticFiles directory are invalid without a trailing slash (/
) unless the xref:Microsoft.AspNetCore.StaticFiles.Infrastructure.SharedOptions.RedirectToAppendTrailingSlash option of xref:Microsoft.AspNetCore.Builder.DefaultFilesOptions is used.
The xref:Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider class contains a Mappings property that serves as a mapping of file extensions to MIME content types. In the following sample, several file extensions are mapped to known MIME types. The .rtf extension is replaced, and .mp4 is removed:
See MIME 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 types and renders the unknown file as an image:
With the preceding code, a request for a file with an unknown content type is returned as an image.
Warning
Enabling xref:Microsoft.AspNetCore.Builder.StaticFileOptions.ServeUnknownFileTypes is a security risk. It's disabled by default, and its use is discouraged. FileExtensionContentTypeProvider provides a safer alternative to serving files with non-standard extensions.
Consider the following Razor page which displays the /MyStaticFiles/image3.png
file:
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. The following example calls UseStaticFiles
twice to serve files from both wwwroot
and MyStaticFiles
:
Using the preceding code:
- The
/MyStaticFiles/image3.png
file is displayed. - The Image Tag Helpers xref:Microsoft.AspNetCore.Mvc.TagHelpers.ImageTagHelper.AppendVersion is not applied because the Tag Helpers depend on xref:Microsoft.AspNetCore.Hosting.IWebHostEnvironment.WebRootFileProvider.
WebRootFileProvider
has not been updated to include theMyStaticFiles
folder.
The following code updates the WebRootFileProvider
, which enables the Image Tag Helper to provide a version:
Note
The preceding approach applies to Razor Pages and MVC apps. For guidance that applies to Blazor Web Apps, see xref:blazor/fundamentals/static-files#serve-files-from-multiple-locations.
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
,UseStaticFiles
, andMapStaticAssets
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
.cs
and.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.
When xref:Microsoft.AspNetCore.Hosting.IWebHostEnvironment.WebRootPath%2A?displayProperty=nameWithType is set to a folder other than wwwroot
:
- In the development environment, static assets found in both
wwwroot
and the updatedIWebHostEnvironment.WebRootPath
are served fromwwwroot
. - In any environment other than development, duplicate static assets are served from the updated
IWebHostEnvironment.WebRootPath
folder.
Consider a web app created with the empty web template:
-
Containing an
Index.html
file inwwwroot
andwwwroot-custom
. -
With the following updated
Program.cs
file that setsWebRootPath = "wwwroot-custom"
:
In the preceding code, requests to /
:
- In the development environment return
wwwroot/Index.html
- In any environment other than development return
wwwroot-custom/Index.html
To ensure assets from wwwroot-custom
are returned, use one of the following approaches:
-
Delete duplicate named assets in
wwwroot
. -
Set
"ASPNETCORE_ENVIRONMENT"
inProperties/launchSettings.json
to any value other than"Development"
. -
Completely disable static web assets by setting
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
in the 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 IWebHostEnvironment.WebRootPath
to a non development value, guaranteeing duplicate content is returned from wwwroot-custom
rather than wwwroot
:
- View or download sample code (how to download)
- Middleware
- Introduction to ASP.NET Core
- xref:blazor/file-uploads
- xref:blazor/file-downloads
:::moniker-end