dotnet / dotnet/aspnetcore

[Static web assets] Support for fallbacks and default files

Open
#64,828 0 comments 0 reactions 0 assignees View on GitHub
area-blazor feature-static-web-assets
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

## Summary

Add support for default file serving (``) and SPA fallback routing (``) in the StaticWebAssets SDK, providing feature parity with `UseDefaultFiles()` and `MapFallbackToFile()` for apps using `MapStaticAssets()`.

## Motivation and goals

- **Default Files Gap**: Currently, `MapStaticAssets()` doesn't support serving default documents (like `index.html`) when a directory path is requested. Developers using the new `.NET 9+` static assets pipeline must either:
- Continue using `UseDefaultFiles()` middleware before `MapStaticAssets()` (mixing paradigms)
- Manually configure additional routes for their default pages

- **SPA Fallback Gap**: Single Page Applications (SPAs) require fallback routing where non-file requests (e.g., `/about`, `/users/123`) are served by a single entry point file (typically `index.html`). The existing `MapFallbackToFile("index.html")` works with `UseStaticFiles()` but not with the optimized `MapStaticAssets()` pipeline.

- **Consistency**: The StaticWebAssets SDK should support common static file scenarios at build-time, enabling the full optimization benefits (compression, fingerprinting, ETags) for these patterns.

## In scope

1. **Default Files Support (``)**: When a request matches a directory path (e.g., `/` or `/admin/`), serve a configured default file from that directory
- Support configuring one or more default file names
- Generate additional endpoints at build time for directory-to-file mappings

2. **SPA Fallback Support (``)**: Add a catch-all fallback endpoint `{**slug}` that serves a specified file for non-file requests
- Useful for client-side routing in SPAs (React, Angular, Vue, Blazor WASM standalone)
- Should work with fingerprinted assets while serving the non-fingerprinted fallback path

## Out of scope

- Directory browsing functionality (`UseDirectoryBrowser`) - this is a runtime-only feature that lists directory contents dynamically
- Custom request path mappings (serve files from non-webroot locations) - can be achieved with existing `PhysicalFileProvider` configuration
- `UseFileServer()` combined middleware replacement - out of scope for initial implementation

## Risks / unknowns

1. **Endpoint Ordering**: The fallback endpoint must have the lowest priority (`int.MaxValue` order) to avoid matching before other routes. Need to ensure this integrates correctly with other mapped endpoints.

2. **Non-file Route Constraint**: The fallback pattern should use `:nonfile` route constraint (like `MapFallbackToFile` does) to allow requests with file extensions to 404 naturally. Need to validate this works with the generated endpoints.

3. **Fingerprinted vs Non-fingerprinted**: Default files and fallback files may reference fingerprinted assets internally. The entry point itself typically shouldn't be fingerprinted (need stable URL), but should still benefit from compression and ETags.

4. **Multiple Entry Points**: Some apps may have multiple SPAs or sections with different fallback files (e.g., `/admin/{**slug}` → `admin/index.html`). Should we support path-specific fallbacks?

5. **Developer Confusion**: Developers might set both properties incorrectly. Clear documentation needed on:
- Default files: "Serve `index.html` when user visits `/`"
- Fallback: "Serve `index.html` for any unmatched route like `/about` or `/products/123`"

## Examples

### Default Files Configuration

```xml


index.html

```

**Behavior**:
- Request to `/` → serves `wwwroot/index.html`
- Request to `/admin/` → serves `wwwroot/admin/index.html` (if exists)

**Equivalent middleware today**:
```csharp
app.UseDefaultFiles();
app.MapStaticAssets();
```

### SPA Fallback Configuration

```xml


index.html

```

**Behavior**:
- Request to `/about` → serves `wwwroot/index.html` (no file extension, no matching route)
- Request to `/products/123` → serves `wwwroot/index.html`
- Request to `/styles.css` → serves the actual CSS file (file extension, not fallback)
- Request to `/images/logo.png` → serves the actual image (file extension, not fallback)

**Equivalent middleware today**:
```csharp
app.MapStaticAssets();
app.MapFallbackToFile("index.html");
```

### Combined Configuration (Typical SPA)

```xml

index.html
index.html

```

### Advanced: Multiple Default Files (future consideration)

```xml


index.html;default.html

```

### Comparison with Current Static Files Middleware

| Feature | StaticFiles Middleware | Proposed StaticWebAssets SDK |
|---------|----------------------|------------------------------|
| Default files | `app.UseDefaultFiles()` | `` |
| Fallback routing | `app.MapFallbackToFile("index.html")` | `` |
| Compression | ❌ Runtime only | ✅ Build-time Gzip/Brotli |
| Fingerprinting | ❌ Not supported | ✅ Content-based fingerprinting |
| ETags | Runtime computed | Build-time computed |

Contributor guide

Open the contributing guide

Research direction

Start by tracing the StaticWebAssets SDK entry point and the existing MapStaticAssets(), UseDefaultFiles(), and MapFallbackToFile() behaviors described here. Resolve the endpoint ordering, nonfile constraint, fingerprinting, and configuration questions before implementation. Done means supporting the requested default-file and SPA-fallback scenarios while leaving the listed out-of-scope features unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
build-system, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.