AspNetCore.Docs icon indicating copy to clipboard operation
AspNetCore.Docs copied to clipboard

Default documents are not served when using MapStaticAssets() when default web-root is changed ...

Open bdcoder2 opened this issue 3 months ago • 3 comments

Description

When using .NET 9.0, according to the documentation:

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.

However, it appears MapStaticAssets DOES NOT serve default documents. For example, if the web root is changed, i.e.:

web_app_options = new WebApplicationOptions()
{

   WebRootPath = Path.Combine( content_root_path, @"www" );

};

web_app_builder = WebApplication.CreateBuilder( web_app_options );

and middleware is configured as per the documentation (that is, use MapStaticAssets instead of UseStaticFiles), i.e.:

default_file_opts = new();

default_file_opts.DefaultFileNames.Clear();

default_file_opts.DefaultFileNames.Add( "index.html" );

app.UseDefaultFiles( default_file_opts );

app.MapStaticAssets();

When the app is run, a request to "/" should serve the "index.html" file, but instead the server responds with a 404 error!

However, by adding a call to UseStaticFiles(), the app works as expected, i.e.:

default_file_opts = new();

default_file_opts.DefaultFileNames.Clear();

default_file_opts.DefaultFileNames.Add( "index.html" );

app.UseDefaultFiles( default_file_opts );

app.UseStaticFiles();

app.MapStaticAssets();

The code above works, but what is the point of MapStaticAssets then? Given that UseStaticFiles is terminal, does MapStaticAssets do anything?

The documentation needs to include:

  1. Clarity on how to serve default documents when using MapStaticAssets WITHOUT using UseStaticFiles (if possible?)

  2. Documentation for the manifest file used by MapStaticAssets (couldn't seem to find any).

Thank-you in advance.

Page URL

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-9.0#serve-default-documents

Content source URL

https://github.com/dotnet/AspNetCore.Docs/blob/main/aspnetcore/fundamentals/static-files.md

Document ID

3fec6e08-fc99-7a5c-796f-3f2347cad891

Platform Id

5c42c2c8-be1b-60de-8cde-f9b8d8c24f5f

Article author

@wadepickett

Metadata

  • ID: d47f38e2-bc36-cfb8-b0cc-17a534689f8b
  • PlatformId: 5c42c2c8-be1b-60de-8cde-f9b8d8c24f5f
  • Service: aspnet-core
  • Sub-service: fundamentals

Related Issues

bdcoder2 avatar Oct 09 '25 20:10 bdcoder2

Rough analysis, verify before proceeding on the PR:

Issue Analysis: Default Documents Not Served with MapStaticAssets When Web-Root Is Changed

Issue Summary

This is a valid issue. The documentation states that UseDefaultFiles should work to serve default files, but when using MapStaticAssets() instead of UseStaticFiles() with a custom web root path, the default files aren't being served.

Target Version

  • .NET 9.0
  • The issue specifically mentions using MapStaticAssets() which was introduced in .NET 9.0

Issue Analysis

The user is reporting that when:

  1. The web root path is changed from the default (wwwroot) to a custom path
  2. UseDefaultFiles() is configured with default file options
  3. MapStaticAssets() is used instead of UseStaticFiles()

The application fails to serve default documents like "index.html" when a request is made to the root "/". Instead, a 404 error is returned.

The user has verified that adding UseStaticFiles() to the pipeline solves the issue:

app.UseDefaultFiles(default_file_opts);
app.UseStaticFiles();
app.MapStaticAssets();

This behavior is inconsistent with what's documented, as the documentation states:

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.

Documentation Issue

The documentation is incomplete regarding how MapStaticAssets() interacts with UseDefaultFiles(). It doesn't clearly explain that MapStaticAssets() does not handle default documents by itself, unlike UseStaticFiles().

In static-files.md, lines 35-72 describe the features and benefits of MapStaticAssets() but don't clarify this important limitation. Line 57-58 even states:

Map Static Assets can replace xref:Microsoft.AspNetCore.Builder.StaticFileExtensions.UseStaticFiles%2A in most situations.

However, this appears not to be true for serving default documents when a custom web root is used.

Required Changes

The documentation should be updated to include:

  1. In aspnetcore/fundamentals/static-files.md:

    • Add explicit information about the limitations of MapStaticAssets() regarding default documents
    • Clarify that UseDefaultFiles() requires UseStaticFiles() to function when using a custom web root, and that MapStaticAssets() doesn't handle this scenario
    • Update lines 797-814 (Serve default documents section) to clarify this behavior
  2. Add documentation about the manifest file used by MapStaticAssets() as requested by the user.

Code Verification

The user has properly identified the workaround by including UseStaticFiles() in the middleware pipeline. This approach works because UseStaticFiles() handles the default file redirection after UseDefaultFiles() determines which file to serve.

Recommendation

Update the documentation to clarify this behavior and provide explicit guidance on how to properly serve default documents when using MapStaticAssets() with a custom web root. The documentation should explain that in some scenarios, including default document handling with custom web roots, UseStaticFiles() is still required alongside MapStaticAssets().

wadepickett avatar Oct 13 '25 17:10 wadepickett

@bdcoder2, Thanks very much for bringing this up and providing details. We will improve this topic.

wadepickett avatar Oct 13 '25 17:10 wadepickett

No problem! Thanks for addressing the issue promptly!

Currently I include the following comments in my code when configuring middleware to serve default / static files:

/*
IMPORTANT:
The UseDefaultFiles method must be called BEFORE the UseStaticFiles method
to serve the default file. UseDefaultFiles is a URL rewriter that does not
actually serve the file ...
*/

default_file_opts = new();

default_file_opts.DefaultFileNames.Clear();

default_file_opts.DefaultFileNames.Add( "index.html" );

app.UseDefaultFiles( default_file_opts );


/*
IMPORTANT:
UseStaticFiles() will serve static files in the <web-root> folder only and
from any sub-directories within the <web-root>. 

Static files are typically located in the <web-root> folder, which is typically
located outside of the <content-root> folder for security purposes.
*/

app.UseStaticFiles();


/*
The MapStaticAssets() method in ASP.NET Core, introduced in .NET 9, is 
designed to efficiently serve static web assets known at build and 
publish time. However, it DOES NOT inherently serve default files like 
index.html or default.html when a directory is requested without a 
specific file name. This functionality is typically provided by the 
UseDefaultFiles middleware, which works in conjunction with UseStaticFiles.

To serve default files in an ASP.NET Core application using MapStaticAssets, 
it is necessary to combine MapStaticAssets with UseStaticFiles and UseDefaultFiles.

To configure the application's request pipeline in Program.cs to serve
default files:

1. Enable Default Files: 
   Call app.UseDefaultFiles() before app.UseStaticFiles() to allow the 
   application to serve a default file (e.g.: index.html) when a 
   directory is requested.

2. Enable Static Files: 
   Call app.UseStaticFiles() to enable serving static files from the web
   root directory.

3. Map Static Assets: 
   Call app.MapStaticAssets() to leverage the performance benefits of 
   optimized static asset delivery for assets known at build/publish 
   time. 

The following line can be commented out and static files will be served 
just fine.  Waiting on more documentation with regard to MapStaticAssets.
*/
// app.MapStaticAssets();

bdcoder2 avatar Oct 13 '25 17:10 bdcoder2