How to Serve Files with ASP.NET Core FileProviders: A Complete Guide

ASP.NET Core abstracts file access through the IFileProvider interface, enabling you to serve content from physical disks, embedded resources, or custom sources without changing middleware logic.

The dotnet/aspnetcore repository implements a flexible file serving pipeline built on the IFileProvider abstraction. This design allows the framework to serve static files, compile Razor views, and resolve Tag Helper glob patterns using a unified interface. Whether you are exposing files from the local filesystem, embedded assembly resources, or a custom cloud storage backend, understanding these providers is essential for building maintainable ASP.NET Core applications.

Understanding the IFileProvider Interface

The IFileProvider interface defines the contract for all file access in ASP.NET Core. It exposes methods to retrieve IFileInfo and IDirectoryContents for a given virtual path, isolating your application from specific storage implementations.

According to the source code in src/Middleware/StaticFiles/src/StaticFileMiddleware.cs, the middleware delegates all file resolution to an IFileProvider instance configured through StaticFileOptions. This means the middleware itself contains no filesystem-specific logic—it simply asks the provider for a file and streams the result if found.

Built-in FileProvider Implementations

ASP.NET Core ships with three primary implementations that cover most scenarios. Each provider implements IFileInfo to expose file metadata and stream access.

PhysicalFileProvider

The PhysicalFileProvider maps virtual paths to a directory on disk. By default, when you call app.UseStaticFiles() without arguments, the framework creates a PhysicalFileProvider pointing to the web root (wwwroot) folder.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStaticFiles(); // Uses PhysicalFileProvider for wwwroot
app.Run();

EmbeddedFileProvider

The EmbeddedFileProvider serves files compiled into an assembly as embedded resources. This is ideal for serving static assets from class libraries or plugins where you cannot rely on external files.

var embeddedProvider = new EmbeddedFileProvider(
    typeof(Program).Assembly, "MyApp.Embedded");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = embeddedProvider,
    RequestPath = "/embedded"
});

CompositeFileProvider

The CompositeFileProvider merges multiple providers into a single logical view. When resolving a path, it queries providers in the order specified and returns the first match found.

var composite = new CompositeFileProvider(
    new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "wwwroot")),
    new EmbeddedFileProvider(typeof(Program).Assembly, "MyApp.Embedded"));

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = composite
});

Configuring Static File Middleware

The StaticFileMiddleware (defined in src/Middleware/StaticFiles/src/StaticFileMiddleware.cs) handles HTTP requests for static content. It uses StaticFileOptions (located in src/Middleware/StaticFiles/src/StaticFileOptions.cs) to determine which IFileProvider to query and how to map request paths to virtual paths.

When a request arrives, the middleware calls FileProvider.GetFileInfo(requestPath). If the returned IFileInfo has Exists == true and IsDirectory == false, the middleware streams the file to the response with appropriate content-type headers, caching directives, and range request support.

To serve files from a custom directory outside of wwwroot, configure the options explicitly:

var env = app.Environment;
var customProvider = new PhysicalFileProvider(
    Path.Combine(env.ContentRootPath, "SharedFiles"));

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = customProvider,
    RequestPath = "/shared"
});

FileProviders in Razor and Tag Helpers

Beyond static file serving, the IFileProvider abstraction powers other subsystems in the dotnet/aspnetcore framework.

Razor Runtime Compilation

In src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs, the FileProviderRazorProjectFileSystem bridges Razor's project system to an IFileProvider. This allows the runtime compiler to locate and watch .cshtml files for changes, even when those files reside in non-standard locations.

builder.Services.AddRazorPages()
    .AddRazorRuntimeCompilation(options =>
    {
        options.FileProviders.Add(
            new PhysicalFileProvider(
                Path.Combine(env.ContentRootPath, "RazorPages")));
    });

Tag Helper Globbing

The globbing infrastructure for Tag Helpers (such as <script src="~/js/**/*.js">) relies on FileProviderGlobbingFile.cs and FileProviderGlobbingDirectory.cs in src/Mvc/Mvc.TagHelpers/src/. These classes adapt the IFileProvider interface to the globbing pattern matcher, enabling wildcard expansion over any file provider implementation.

Summary

  • IFileProvider is the core abstraction that decouples ASP.NET Core from specific storage implementations.
  • Use PhysicalFileProvider for disk-based files, EmbeddedFileProvider for assembly resources, and CompositeFileProvider to combine multiple sources.
  • Configure StaticFileOptions to customize the FileProvider used by StaticFileMiddleware for serving static content.
  • The same abstraction supports Razor runtime compilation and Tag Helper globbing through adapter classes like FileProviderRazorProjectFileSystem.

Frequently Asked Questions

What is the default FileProvider when calling UseStaticFiles()?

When you invoke app.UseStaticFiles() without arguments, ASP.NET Core automatically creates a PhysicalFileProvider that points to the application's web root directory (typically wwwroot). This provider handles all requests to static files unless you explicitly override it in StaticFileOptions.

Can I serve files from outside the web root folder?

Yes. Create a new PhysicalFileProvider instance pointing to your desired directory and pass it to StaticFileOptions.FileProvider. Set the RequestPath property to specify the URL prefix that maps to this location, allowing you to serve files from any accessible path on the filesystem.

How do I serve files embedded in a Razor Class Library?

Use the EmbeddedFileProvider from the Microsoft.Extensions.FileProviders.Embedded namespace. Pass the assembly containing your resources and the optional namespace prefix to the constructor, then register it in StaticFileOptions or as part of a CompositeFileProvider if you need to merge it with physical files.

Why would I need a custom IFileProvider implementation?

Custom implementations allow you to serve files from sources not supported by the built-in providers, such as cloud storage services (Azure Blob Storage, AWS S3), databases, or network shares. Because StaticFileMiddleware and Razor compilation only depend on the IFileProvider interface, swapping the implementation requires no changes to the consuming code.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →