Skip to content

Commit 290a862

Browse files
Split static files and MapStaticFiles into 2 doc /1 (#34924)
* Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * Split static files and MapStaticFiles into 2 doc /1 * work * work * work * Apply suggestions from code review Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com> * react to feedback/final tasks * react to feedback/final tasks * react to feedback/final tasks --------- Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com>
1 parent bc63502 commit 290a862

3 files changed

Lines changed: 49 additions & 180 deletions

File tree

Lines changed: 31 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
---
2-
title: Static files in ASP.NET Core
2+
title: Map static files in ASP.NET Core
33
author: rick-anderson
4-
description: Learn how to serve and secure static files and configure static file hosting middleware behaviors in an ASP.NET Core web app.
5-
monikerRange: '>= aspnetcore-3.1'
4+
description: Learn how to serve and secure mapped static files and configure static file hosting middleware behaviors in an ASP.NET Core web app.
5+
monikerRange: '>= aspnetcore-8.0'
66
ms.author: riande
77
ms.custom: mvc
8-
ms.date: 7/25/2024
9-
uid: fundamentals/static-files
8+
ms.date: 3/18/2025
9+
uid: fundamentals/map-static-files
1010
---
11-
# Static files in ASP.NET Core
1211

13-
[!INCLUDE[](~/includes/not-latest-version.md)]
12+
# Map static files in ASP.NET Core
1413

1514
:::moniker range=">= aspnetcore-9.0"
1615

@@ -53,8 +52,28 @@ Creating performant web apps requires optimizing asset delivery to the browser.
5352
* Integrates the information gathered about static web assets during the build and publish process with a runtime library that processes this information to optimize file serving to the browser.
5453
* 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.
5554

56-
[`UseStaticFiles`](/dotnet/api/microsoft.aspnetcore.builder.staticfileextensions.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
57-
](xref:aspnetcore-9#optimizing-static-web-asset-delivery).
55+
### `MapStaticAssets` versus `UseStaticFiles`
56+
57+
<xref:Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssets%2A> is available in ASP.NET Core in .NET 9.0 and later. <xref:Microsoft.AspNetCore.Builder.StaticFileExtensions.UseStaticFiles%2A> must be used in versions prior to .NET 9.0.
58+
59+
<xref:Microsoft.AspNetCore.Builder.StaticFileExtensions.UseStaticFiles%2A> serves static files, but it doesn't provide the same level of optimization as `MapStaticAssets`. `MapStaticAssets` is 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, `UseStaticFiles` should be used.
60+
61+
The following features are supported in `UseStaticFiles` but not in `MapStaticAssets`:
62+
63+
* [Serving files from disk or embedded resources, or other locations](xref:fundamentals/static-files#serve-files-from-multiple-locations)
64+
* [Serve files outside of web root](xref:fundamentals/static-files#serve-files-outside-of-web-root)
65+
* [Set HTTP response headers](xref:fundamentals/static-files#set-http-response-headers)
66+
* [Directory browsing](xref:fundamentals/static-files#directory-browsing)
67+
* [Serve default documents](xref:fundamentals/static-files#serve-default-documents)
68+
* [`FileExtensionContentTypeProvider`](xref:fundamentals/static-files#fileextensioncontenttypeprovider)
69+
* [Serve files from multiple locations](xref:fundamentals/static-files#serve-files-from-multiple-locations)
70+
* [Serving files from disk or embedded resources, or other locations](xref:fundamentals/static-files#serve-files-from-multiple-locations)
71+
* [Serve files outside of web root](xref:fundamentals/static-files#serve-files-outside-of-web-root)
72+
* [Set HTTP response headers](xref:fundamentals/static-files#set-http-response-headers)
73+
* [Directory browsing](xref:fundamentals/static-files#directory-browsing)
74+
* [Serve default documents](xref:fundamentals/static-files#serve-default-documents)
75+
* [`FileExtensionContentTypeProvider`](xref:fundamentals/static-files#fileextensioncontenttypeprovider)
76+
* [Serve files from multiple locations](xref:fundamentals/static-files#serve-files-from-multiple-locations)
5877

5978
### Serve files in web root
6079

@@ -92,7 +111,7 @@ The following markup references `MyStaticFiles/images/red-rose.jpg`:
92111
<!-- zz test via /Home2/MyStaticFilesRR -->
93112
[!code-html[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Views/Home2/MyStaticFilesRR.cshtml?range=1)]
94113

95-
To serve files from multiple locations, see [Serve files from multiple locations](#serve-files-from-multiple-locations).
114+
To serve files from multiple locations, see [Serve files from multiple locations](xref:fundamentals/static-files#serve-files-from-multiple-locations).
96115

97116
### Set HTTP response headers
98117

@@ -104,154 +123,12 @@ The preceding code makes static files publicly available in the local cache for
104123

105124
## Static file authorization
106125

107-
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:
126+
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 `MapStaticAssets` is called before the authorization middleware:
108127

109128
* No authorization checks are performed on the static files.
110129
* Static files served by the Static File Middleware, such as those under `wwwroot`, are publicly accessible.
111130

112-
To serve static files based on authorization:
113-
114-
* Store them outside of `wwwroot`.
115-
* Call `UseStaticFiles`, specifying a path, after calling `UseAuthorization`.
116-
* Set the [fallback authorization policy](xref:Microsoft.AspNetCore.Authorization.AuthorizationOptions.FallbackPolicy).
117-
118-
<!-- ~/fundamentals/static-files/samples/8.x/StaticFileAuth is a different app that ~/fundamentals/static-files/samples/6.x/StaticFileAuth -->
119-
[!code-csharp[](~/fundamentals/static-files/samples/6.x/StaticFileAuth/Program.cs?name=snippet_auth&highlight=18-23,38,45-50)]
120-
121-
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.
122-
123-
<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.
124-
125-
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](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/static-files/samples/8.x) demonstrates this.
126-
127-
An alternative approach to serve files based on authorization is to:
128-
129-
* Store them outside of `wwwroot` and any directory accessible to the Static File Middleware.
130-
* Serve them via an action method to which authorization is applied and return a <xref:Microsoft.AspNetCore.Mvc.FileResult> object:
131-
132-
133-
[!code-csharp[](~/fundamentals/static-files/samples/6.x/StaticFileAuth/Pages/BannerImage.cshtml.cs?name=snippet)]
134-
135-
The preceding approach requires a page or endpoint per file. The following code returns files or uploads files for authenticated users:
136-
137-
:::code language="csharp" source="~/fundamentals/static-files/samples/9.x/StaticFileAuth/Program.cs" id="snippet_1":::
138-
139-
IFormFile in the preceding sample uses memory buffer for uploading. For handling large file use streaming. See [Upload large files with streaming](xref:mvc/models/file-uploads#upload-large-files-with-streaming).
140-
141-
See the [StaticFileAuth](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/static-files/samples/9.x/StaticFileAuth) GitHub folder for the complete sample.
142-
143-
## Directory browsing
144-
145-
Directory browsing allows directory listing within specified directories.
146-
147-
Directory browsing is disabled by default for security reasons. For more information, see [Security considerations for static files](#security-considerations-for-static-files).
148-
149-
Enable directory browsing with <xref:Microsoft.Extensions.DependencyInjection.DirectoryBrowserServiceExtensions.AddDirectoryBrowser%2A> and <xref:Microsoft.AspNetCore.Builder.DirectoryBrowserExtensions.UseDirectoryBrowser%2A>:
150-
151-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_db&highlight=9,23-37)]
152-
153-
<!-- Select RP Home > Directory browsing -->
154-
The preceding code allows directory browsing of the *wwwroot/images* folder using the URL `https://<hostname>/MyImages`, with links to each file and folder:
155-
156-
![directory browsing](~/fundamentals/static-files/_static/dir-browse.png)
157-
158-
`AddDirectoryBrowser` [adds services](https://github.com/dotnet/aspnetcore/blob/fc4e391aa58a9fa67fdc3a96da6cfcadd0648b17/src/Middleware/StaticFiles/src/DirectoryBrowserServiceExtensions.cs#L25) 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.
159-
160-
## Serve default documents
161-
162-
<!-- Comment out @*@page*@ default RP file -->
163-
164-
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:
165-
166-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_df&highlight=16)]
167-
168-
`UseDefaultFiles` must be called before `UseStaticFiles` to serve the default file. `UseDefaultFiles` is a URL rewriter that doesn't serve the file.
169-
170-
With `UseDefaultFiles`, requests to a folder in `wwwroot` search for:
171-
172-
* `default.htm`
173-
* `default.html`
174-
* `index.htm`
175-
* `index.html`
176-
177-
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](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs), a request to `https://localhost:<port>/def/` serves `default.html` from `wwwroot/def`.
178-
179-
The following code changes the default file name to `mydefault.html`:
180-
181-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_df2&highlight=16-19)]
182-
183-
### UseFileServer for default documents
184-
185-
<xref:Microsoft.AspNetCore.Builder.FileServerExtensions.UseFileServer*> combines the functionality of `UseStaticFiles`, `UseDefaultFiles`, and optionally `UseDirectoryBrowser`.
186-
187-
Call `app.UseFileServer` to enable the serving of static files and the default file. Directory browsing isn't enabled:
188-
189-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_ufs&highlight=16)]
190-
191-
The following code enables the serving of static files, the default file, and directory browsing:
192-
193-
<!-- app.UseFileServer(enableDirectoryBrowsing: true); returns the default HTML doc before the default Razor Page - ie, / returns the default HTML file, not Pages/Index.cshtml --
194-
But when using app.UseDefaultFiles();, I need to comment out Pages/Index.cshtml or / returns Pages/Index.cshtml, not the default HTML file.
195-
-->
196-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_ufs2&highlight=6,18)]
197-
198-
Consider the following directory hierarchy:
199-
200-
* `wwwroot`
201-
* `css`
202-
* `images`
203-
* `js`
204-
* `MyStaticFiles`
205-
* `defaultFiles`
206-
* `default.html`
207-
* `image3.png`
208-
* `images`
209-
* `MyImage.jpg`
210-
211-
The following code enables the serving of static files, the default file, and directory browsing of `MyStaticFiles`:
212-
213-
<!-- https://localhost:44391/StaticFiles/ or the link on https://localhost:44391/Home2/MyStaticFilesRR -->
214-
215-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_tree&highlight=1,8,22-28)]
216-
217-
<xref:Microsoft.Extensions.DependencyInjection.DirectoryBrowserServiceExtensions.AddDirectoryBrowser%2A> must be called when the `EnableDirectoryBrowsing` property value is `true`.
218-
219-
Using the preceding file hierarchy and code, URLs resolve as follows:
220-
221-
| URI | Response |
222-
| ------- | ------|
223-
| `https://<hostname>/StaticFiles/images/MyImage.jpg` | `MyStaticFiles/images/MyImage.jpg` |
224-
| `https://<hostname>/StaticFiles` | directory listing |
225-
| `https://<hostname>/StaticFiles/defaultFiles` | `MyStaticFiles/defaultFiles/default.html` |
226-
| `https://<hostname>/StaticFiles/defaultFiles/image3.png` | `MyStaticFiles/defaultFiles//image3.png` |
227-
228-
If no default-named file exists in the *MyStaticFiles* directory, `https://<hostname>/StaticFiles` returns the directory listing with clickable links:
229-
230-
![Static files list](~/fundamentals/static-files/_static/db2.png)
231-
232-
<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.
233-
234-
## FileExtensionContentTypeProvider
235-
236-
The <xref:Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider> class contains a [Mappings](/dotnet/api/microsoft.aspnetcore.staticfiles.fileextensioncontenttypeprovider.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:
237-
238-
<!-- test via /mapTest/image1.image and mapTest/test.htm3 /mapTest/TextFile.rtf -->
239-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_fec&highlight=19-33)]
240-
241-
See [MIME content types](https://www.iana.org/assignments/media-types/media-types.xhtml).
242-
243-
## Non-standard content types
244-
245-
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.
246-
247-
The following code enables serving unknown types and renders the unknown file as an image:
248-
249-
[!code-csharp[](~/fundamentals/static-files/samples/9.x/StaticFilesSample/Program.cs?name=snippet_ns&highlight=16-20)]
250-
251-
With the preceding code, a request for a file with an unknown content type is returned as an image.
252-
253-
> [!WARNING]
254-
> Enabling <xref:Microsoft.AspNetCore.Builder.StaticFileOptions.ServeUnknownFileTypes> is a security risk. It's disabled by default, and its use is discouraged. [FileExtensionContentTypeProvider](#fileextensioncontenttypeprovider) provides a safer alternative to serving files with non-standard extensions.
131+
To serve static files based on authorization, see [Static file authorization](xref:fundamentals/static-files#static-file-authorization).
255132

256133
## Serve files from multiple locations
257134

@@ -275,27 +152,6 @@ The following code updates the `WebRootFileProvider`, which enables the Image Ta
275152
> [!NOTE]
276153
> 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>.
277154
278-
<a name="sc"></a>
279-
280-
### Security considerations for static files
281-
282-
> [!WARNING]
283-
> `UseDirectoryBrowser` and `UseStaticFiles` <!-- but not MapStaticAssets --> 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.
284-
285-
* The URLs for content exposed with `UseDirectoryBrowser`, `UseStaticFiles`, and `MapStaticAssets` 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.
286-
287-
* ASP.NET Core apps hosted in IIS use the [ASP.NET Core Module](xref:host-and-deploy/aspnet-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.
288-
289-
* Complete the following steps in IIS Manager to remove the IIS static file handler at the server or website level:
290-
1. Navigate to the **Modules** feature.
291-
1. Select **StaticFileModule** in the list.
292-
1. Click **Remove** in the **Actions** sidebar.
293-
294-
> [!WARNING]
295-
> 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.
296-
297-
* Place code files, including `.cs` and `.cshtml`, outside of the app project's [web root](xref:fundamentals/index#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.
298-
299155
## Serve files outside wwwroot by updating IWebHostEnvironment.WebRootPath
300156

301157
When <xref:Microsoft.AspNetCore.Hosting.IWebHostEnvironment.WebRootPath%2A?displayProperty=nameWithType> is set to a folder other than `wwwroot`:
@@ -341,7 +197,3 @@ The following code updates `IWebHostEnvironment.WebRootPath` to a non developmen
341197
* <xref:blazor/file-downloads>
342198

343199
:::moniker-end
344-
345-
[!INCLUDE[](~/fundamentals/static-files/includes/static-files8.md)]
346-
347-
[!INCLUDE[](~/fundamentals/static-files/includes/static-files6.md)]

aspnetcore/fundamentals/static-files/includes/static-files8.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
:::moniker range="= aspnetcore-8.0"
1+
:::moniker range=">= aspnetcore-8.0"
22

33
By [Rick Anderson](https://twitter.com/RickAndMSFT)
44

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: Static files in ASP.NET Core
3+
author: rick-anderson
4+
description: Learn how to serve and secure static files and configure static file hosting middleware behaviors in an ASP.NET Core web app.
5+
monikerRange: '>= aspnetcore-3.1'
6+
ms.author: riande
7+
ms.custom: mvc
8+
ms.date: 7/25/2024
9+
uid: fundamentals/static-files
10+
---
11+
# Static files in ASP.NET Core
12+
13+
[!INCLUDE[](~/includes/not-latest-version.md)]
14+
15+
[!INCLUDE[](~/fundamentals/static-files/includes/static-files8.md)]
16+
17+
[!INCLUDE[](~/fundamentals/static-files/includes/static-files6.md)]

0 commit comments

Comments
 (0)