I was reading an interesting blog post at strathweb.com about his implementation of an Azure Blob Storage IFileProvider for ASP.NET Core and it made me want to take a deeper look into File Providers and fully understand how they work.

What Are File Providers in ASP.NET Core?

There are 3 File Providers that come built into ASP.NET Core:

  • PhysicalFileProvider - used to access static files in your application
  • ManifestEmbeddedFileProvider – used to access files embedded in assemblies
  • CompositeFileProvider - used to compose multiple File Providers together

File Providers are an abstraction over the file system which provide many benefits; one of which is that you can access static files from different sources in your application.

For example, say you are inserting an image tag into your HTML and you add the following tag into a .cshtml file:

<img src="~/images/pear.jpg" alt="pear" />

Using this image tag will sure enough work as long as you have an image named pear.jpg within an images folder in the wwwroot folder. Also, you need to make sure that you set the middleware to use static files app.UseStaticFiles(); in the Configure method of Startup.cs. You can also enter http://localhost:5000/images/pear.jpg into your browser to view the image.

The reason that all that works is because in Program.cs you call WebHost.CreateDefaultBuilder(args) which sets the content root to the current directory:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Let's say for whatever reason, you had another folder at the root of your application called StaticResources. And within that, you had an images folder and within that, you had an image called apple.jpg. Well, because there is no File Provider that knows about this folder, when you visit http://localhost:5000/StaticResources/images/apple.jpg you will just get a 404 error page.

To make this work like you'd hope you'd need to configure another piece of Middleware to add a PhysicalFileProvider to the Configure method:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "StaticResources")),
        RequestPath = "/StaticImages" // note the path is StaticImages but the directory is StaticResources
    });
}

You could then use this image tag in your .cshtml file to display images from within the StaticResources folder:

<img src="~/StaticImages/images/apple.jpg" alt="apple" width="400" />

Or visit http://localhost:5000/StaticImages/images/apple.jpg in your browser.

Creating a Custom File Provider

Let's say that we had a set of images hosted on a completely different server somewhere, but in our .cshtml files, we would still like to insert our image tags like so:

<img src="~/OtherServer/images/strawberry.jpg" alt="strawberry" width="400" />

To do this, we can create a custom File Provider, which we will call ImagesFileProvider for lack of a better name. We can then add it to our Startup.cs class by first adding it to DI in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    var imageFileProvider = new ImageFileProvider();
    services.AddSingleton(imageFileProvider);
}

And then we can retrieve the File Provider from the DI framework and add it to the Configure method in Startup.cs as options to a new static files Middleware component:

var imageFileProvider = app.ApplicationServices.GetRequiredService<ImageFileProvider>();

app.UseStaticFiles(new StaticFileOptions()
{
    FileProvider = imageFileProvider,
    RequestPath = "/OtherServer/images"
});

What's Next?

In a future blog post I will go into the implmentation of the ImageFileProvider and how create a class that derives from the IFileProvider interface.