ASP.NET 5 & Static Files

 
 
  • Gérald Barré

A website is composed of static files (CSS, JS, HTML, others) and dynamic pages. In this post, we will focus on the static files. In the good old days to serve static files, it was enough to copy it in a folder of the web project and it was directly accessible once the site hosted in IIS. With ASP.NET 5 things change. Indeed it is necessary to activate all the needed functionalities using Middleware. To expose static files, you must activate the StaticFiles middleware.

#StaticFiles middleware

Let's start by adding the reference to StaticFiles. For that we simply add the following line in the project.json file:

JSON
{
    "dependencies": {
        "Microsoft.AspNet.StaticFiles": "1.0.0-beta3"
    }
}

Then we can add the OWIN Middleware:

C#
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
    app.UseStaticFiles();
}

We can now access the files of the site. For example, the URL http://localhost/css/site.css returns the file wwwroot/css/site.css:

This answers the majority of needs but we will explore a little more and see how the UseStaticFiles extension method works.

#Personalization

The UseStaticFiles method has an optional parameter to specify different options:

C#
StaticFileOptions staticFileOptions = new StaticFileOptions();
staticFileOptions.FileProvider = new PhysicalFileProvider("/files");
staticFileOptions.ContentTypeProvider = new FileExtensionContentTypeProvider();
staticFileOptions.DefaultContentType = "text/plain";
staticFileOptions.ServeUnknownFileTypes = false;

app.UseStaticFiles(staticFileOptions);

FileProvider: A class that implements the IFileProvider interface that aims to open a file or enumerate the contents of a folder from a path. A FileProvider does not necessarily use the file system, one can for example create a provider whose files are stored in database.

The default FileProvider is accessible via hostingEnv.WebRootFileProvider (IHostingEnvironment). It uses the FileSystem and points to the wwwroot folder. This folder is not a constant, but is defined (and therefore editable) in the configuration file (project.json) at the webroot property level:

JSON
{
    "webroot": "wwwroot"
}

ContentTypeProvider: A class that implements the IContentTypeProvider interface whose only method is to retrieve the MIME type of a file.

The default content provider provides about 370 associations "file extension"-"MIME type". Although this is a large number it may be missing as needed. If the MIME-type is not known and the ServeUnknownFileTypes option is set to false (the default), the file is not accessible by the client. For example, FontAwesome uses an icon file of type woff2. Because the MIME type for this extension is not set, the client receives a 404 error. To fix this problem, you can define a custom ContentTypeProvider or simpler to add mappings to the default ContentTypeProvider:

C#
var contentTypeProvider = new FileExtensionContentTypeProvider();
if (!contentTypeProvider.Mappings.ContainsKey(".woff2"))
{
    contentTypeProvider.Mappings.Add(".woff2", "application/font-woff2");
}

staticFileOptions.ContentTypeProvider = contentTypeProvider;

#Multiple folders

You can map multiples folders using multiple UseStaticFiles:

C#
app.UseStaticFiles(new StaticFileOptions
{
    RequestPath = new PathString("/css"),
    FileSystem = new PhysicalFileSystem("Public/Styles")
});

app.UseStaticFiles(new StaticFileOptions
{
    RequestPath = new PathString("/js"),
    FileSystem = new PhysicalFileSystem("Public/Scripts")
});

Or you can use a CompositeFileProvider:

C#
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var otherProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "other_folder"));
app.Environment.WebRootFileProvider = new CompositeFileProvider(
    webRootProvider,
    otherProvider);

app.UseStaticFiles();

#Authorization

If some of the files are private, you can ensure the users are logged in before serving the files:

C#
app.Map("/private", privateApp =>
{
    privateApp.Use(async (context, next) =>
    {
        if (!context.User.Identity.IsAuthenticated)
        {
            context.Response.Challenge();
            return;
        }

        await next();
    });

    privateApp.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider("/PrivateDirectory") });
});

#Conclusion

UseStaticFiles allows you to expose the content of a folder to the client. This middleware method is configurable and allows to provide files coming from the file system or any other source such as a database.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub