Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make ASP.NET Core server (Kestrel) case sensitive on Windows

ASP.NET Core apps running in Linux containers use a case sensitive file system, which means that the CSS and JS file references must be case-correct.

However, Windows file system is not case sensitive. Therefore during development you can have CSS and JS files referenced with incorrect casing, and yet they work fine. So you won't know during development on Windows, that your app is going to break when going live on Linux servers.

Is there anyway to make Kestrel on Windows case sensitive, so that we can have consistent behaviour and find the reference bugs before going live?

like image 650
Paymon Avatar asked Apr 30 '18 08:04

Paymon


1 Answers

I fixed that using a middleware in ASP.NET Core. Instead of the standard app.UseStaticFiles() I used:

 if (env.IsDevelopment()) app.UseStaticFilesCaseSensitive();
 else app.UseStaticFiles();

And defined that method as:

/// <summary>
/// Enforces case-correct requests on Windows to make it compatible with Linux.
/// </summary>
public static IApplicationBuilder UseStaticFilesCaseSensitive(this IApplicationBuilder app)
{
    var fileOptions = new StaticFileOptions
    {
        OnPrepareResponse = x =>
        {
            if (!x.File.PhysicalPath.AsFile().Exists()) return;
            var requested = x.Context.Request.Path.Value;
            if (requested.IsEmpty()) return;

            var onDisk = x.File.PhysicalPath.AsFile().GetExactFullName().Replace("\\", "/");
            if (!onDisk.EndsWith(requested))
            {
                throw new Exception("The requested file has incorrect casing and will fail on Linux servers." +
                    Environment.NewLine + "Requested:" + requested + Environment.NewLine +
                    "On disk: " + onDisk.Right(requested.Length));
            }
        }
    };

    return app.UseStaticFiles(fileOptions);
}

Which also uses:

public static string GetExactFullName(this FileSystemInfo @this)
{
    var path = @this.FullName;
    if (!File.Exists(path) && !Directory.Exists(path)) return path;

    var asDirectory = new DirectoryInfo(path);
    var parent = asDirectory.Parent;

    if (parent == null) // Drive:
        return asDirectory.Name.ToUpper();

    return Path.Combine(parent.GetExactFullName(), parent.GetFileSystemInfos(asDirectory.Name)[0].Name);
}
like image 167
Paymon Avatar answered Sep 29 '22 06:09

Paymon