# How Does ASP.NET Core Handle Static Files? Complete Guide to StaticFileMiddleware

> Learn how ASP.NET Core handles static files with StaticFileMiddleware. Discover URL mapping, content streaming, caching, range requests, and compression for optimal performance.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: how-to-guide
- Published: 2026-07-13

---

**ASP.NET Core handles static files through the Static File Middleware (`Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware`), which intercepts HTTP requests, maps URLs to physical files via configurable file providers, and streams content while enforcing HTTP caching, range requests, and compression standards.**

ASP.NET Core serves static content—HTML, CSS, JavaScript, images, and other assets—through a dedicated middleware pipeline component rather than handling them within MVC controllers. Understanding how the framework processes these requests helps developers optimize web application performance and security. This article examines the internal mechanics of static file handling according to the dotnet/aspnetcore source code.

## The Static File Middleware Architecture

The static file serving pipeline centers on three core components in the `Microsoft.AspNetCore.StaticFiles` namespace:

- **StaticFileMiddleware** ([`src/Middleware/StaticFiles/src/StaticFileMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs)) – The main middleware class that performs request validation, path matching, and orchestrates the response.
- **StaticFileContext** ([`src/Middleware/StaticFiles/src/StaticFileContext.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileContext.cs)) – Encapsulates per-request state, handles file lookup, precondition evaluation, range processing, and response header generation.
- **StaticFileOptions** ([`src/Middleware/StaticFiles/src/StaticFileOptions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileOptions.cs)) – Configuration model exposing `RequestPath`, `FileProvider`, `ContentTypeProvider`, and callback hooks.

Developers register the middleware using `app.UseStaticFiles()` (defined in [`StaticFileExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/StaticFileExtensions.cs)), which constructs the middleware with `StaticFileOptions` specifying the request path, file provider (defaulting to `PhysicalFileProvider` pointing at `wwwroot`), content-type provider, and behavior settings.

## Request Processing Pipeline

When an HTTP request enters the pipeline, `StaticFileMiddleware.Invoke(HttpContext)` executes a strict validation sequence before serving content:

1. **Endpoint Validation** – The middleware first checks `ValidateNoEndpointDelegate` to ensure no endpoint was already matched by previous middleware.

2. **Method Validation** – Only **GET** and **HEAD** methods are permitted (`Helpers.IsGetOrHeadMethod`). Other methods cause the request to fall through to subsequent middleware.

3. **Path Matching** – The request path is compared against the configured `RequestPath`. If matched, the remaining path (`subPath`) is extracted for file lookup.

4. **Content-Type Lookup** – The `IContentTypeProvider` (default `FileExtensionContentTypeProvider`) determines the MIME type. If unknown, the request is rejected unless `ServeUnknownFileTypes` is enabled.

5. **File Resolution** – A `StaticFileContext` is instantiated, calling `TryServeStaticFile` which uses the configured `IFileProvider` to locate the physical file via `StaticFileContext.LookupFileInfo`.

6. **HTTP Preconditions** – The context parses `If-Match`, `If-None-Match`, `If-Modified-Since`, and `If-Unmodified-Since` headers, setting `PreconditionState.NotModified` or `PreconditionState.PreconditionFailed` accordingly.

7. **Range Handling** – For GET requests with a valid `Range` header, `ComputeRange` calculates byte ranges and `SendRangeAsync` streams a `206 Partial Content` response. Invalid ranges return `416 Range Not Satisfiable`.

8. **Compression** – When HTTPS compression is enabled (`StaticFileOptions.HttpsCompression`), the middleware sets `IHttpsCompressionFeature` mode via `SetCompressionMode`.

9. **Response Generation** – `ApplyResponseHeadersAsync` writes `ETag`, `Last-Modified`, `Accept-Ranges`, and `Content-Type` headers. If configured, the `OnPrepareResponse` callback executes here.

10. **File Streaming** – Finally, `SendAsync` streams the file (or selected range) using `HttpResponse.SendFileAsync`.

## Configuration and File Providers

By default, ASP.NET Core serves files from the `wwwroot` directory using `PhysicalFileProvider`. You can customize this behavior through `StaticFileOptions`:

```csharp
// Program.cs - Custom static file configuration
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Serve files from custom directory at "/files" URL prefix
app.UseStaticFiles(new StaticFileOptions
{
    RequestPath = "/files",
    FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
    ServeUnknownFileTypes = true,
    DefaultContentType = "application/octet-stream",
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers["X-Static-File"] = "true";
    }
});

app.Run();

```

The **FileExtensionContentTypeProvider** ([`src/StaticFiles/ContentTypeProviders/FileExtensionContentTypeProvider.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/StaticFiles/ContentTypeProviders/FileExtensionContentTypeProvider.cs)) maps file extensions to MIME types. When `ServeUnknownFileTypes` is false (default), files without recognized extensions return a 404 response.

## HTTP Optimization Features

### Caching and Preconditions

The middleware implements full HTTP/1.1 conditional request semantics. It generates `ETag` and `Last-Modified` headers, comparing them against client-provided `If-None-Match` and `If-Modified-Since` headers to return `304 Not Modified` responses when content is fresh.

### Range Requests

For resumable downloads and video streaming, the middleware supports `Range` headers:

- Valid ranges return `206 Partial Content` with the requested byte range.
- Invalid ranges return `416 Range Not Satisfiable`.

### Response Callbacks

The `OnPrepareResponse` action allows modification of headers before transmission:

```csharp
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        var headers = ctx.Context.Response.GetTypedHeaders();
        headers.CacheControl = new CacheControlHeaderValue
        {
            Public = true,
            MaxAge = TimeSpan.FromDays(30)
        };
    }
});

```

## Summary

- **StaticFileMiddleware** processes requests in [`src/Middleware/StaticFiles/src/StaticFileMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/StaticFiles/src/StaticFileMiddleware.cs), validating HTTP methods and paths before delegating to `StaticFileContext`.
- Only **GET** and **HEAD** requests are served; all other methods pass through to subsequent middleware.
- Files are resolved via `IFileProvider` (default `PhysicalFileProvider` for `wwwroot`) and mapped to MIME types through `IContentTypeProvider`.
- The middleware handles HTTP preconditions, generates `ETag` headers, and supports `206 Partial Content` range responses.
- Configuration through `StaticFileOptions` enables custom file providers, unknown file type serving, and response header manipulation via `OnPrepareResponse`.

## Frequently Asked Questions

### What file types can ASP.NET Core serve by default?

ASP.NET Core can serve any file type mapped by `FileExtensionContentTypeProvider`, which includes standard web assets like `.html`, `.css`, `.js`, `.png`, and `.jpg`. Files without recognized extensions return 404 unless you explicitly set `ServeUnknownFileTypes = true` and provide a `DefaultContentType`.

### How do I serve static files from outside the wwwroot folder?

Instantiate a `PhysicalFileProvider` pointing to your custom directory and pass it to `StaticFileOptions.FileProvider`:

```csharp
var provider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "MyAssets"));
app.UseStaticFiles(new StaticFileOptions { FileProvider = provider, RequestPath = "/assets" });

```

### What's the difference between UseStaticFiles and UseFileServer?

`UseStaticFiles()` registers only the `StaticFileMiddleware`. `UseFileServer()` combines `UseStaticFiles()`, `UseDefaultFiles()` (which serves index.html for directory requests), and optionally `UseDirectoryBrowser()` (which generates HTML listings of directory contents) into a single convenience method.

### How does static file caching work in ASP.NET Core?

The middleware automatically generates `ETag` and `Last-Modified` headers based on file timestamps. For custom caching policies, use the `OnPrepareResponse` callback to set `Cache-Control` headers. The middleware also respects `If-None-Match` and `If-Modified-Since` request headers, returning `304 Not Modified` when the client's cached version is current.