Default Static File Extensions in ASP.NET Core

I could not quickly find a default way to get ASP.NET core to process URLs of static files without extensions, so I implemented this untested hack. This addresses the limitation that a request for /page.html would return the content of the static file but a request for /page would return HTTP 404, Not Found. This is probably not the best way and at the very least should be refactored out and made configurable, such as allowing callers to specify extensions and possibly exclusions.

I added the following code to the Configure() method in my Startup class before calling UseStaticFiles(), which enables the webserver to serve static files, and UseDefaultFiles(), which configures the webserver to render index.html from the directory identified by the URL if that URL does not specify a file.

The logic is to invoke the remainder of the middleware pipeline. Afterwards, if the request is 404 and does not appear to specify a filename extension, then check for the existence of a file corresponding to the requested URL but adding the .html extension. If such a file exists, then revert the status code to 200 and rerun the remainder of the pipeline.

This solution may not work if filenames may contain dots (my.file.name.html).

This may not work without UseDefaultFiles(). For example, if the URL specifies a directory (/path) this logic will look for a file with the .html extension matching that directory name (/path.html) rather than looking for an index.html file within that directory (/path/index.html).

app.Use(async (context, next) =>
{
    // call the remainder of the pipeline
    await next.Invoke();

    // if it is not 404, ignore the request
    if (context.Response.StatusCode != 404)
    {
        return;
    }

    // the requested path
    string requestedPath = context.Request.Path;

    // the file name part (may contain slashes at first)
    string name = requestedPath;

    // if the path contains a slash
    int index = requestedPath.LastIndexOf('/');

    // trim it to just the name
    if (index > -1)
    {
        name = requestedPath.Substring(index);
    }

    // if the name already has an extension, ignore the request
    //TODO: dot may not indicate extension...
    if (name.Contains("."))
    {
        return;
    }

    // otherwise, if a corresponding .html file exists,
    // then process the request with that path.
    if (File.Exists(
        env.WebRootPath + requestedPath.Replace("/", "\\") + ".html"))
    {
        context.Response.StatusCode = 200;
        context.Request.Path = requestedPath + ".html";
        await next.Invoke();
    }
});

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: