Minifiera och cacha statiska filer i ASP.NET Core

I det här inlägget beskrivs hur du kan minifiera och cacha statiska filer i ASP.NET Core. Du kanske vill göra detta för att göra din webbplats snabbare och därmed förbättra hemsidan placering sökresultaten (SEO).

En viktig sak att tänka på innan du cachar statiska filer är att du behöver en metod för att invalidera cacheminnet när dina statiska filer ändras. Varje statisk fil som du sparar kan ha ett unikt namn som ett GUID, du kan också lägga till en parameter till filnamnet som är unik för varje ny version av filen. Du kan använda en kombination av dessa metoder, bilder kan ha GUID-namn och du kan använda en versionsparameter för andra filer.

Bundler och minifier

Jag använder ett NuGet-paket som heter BuildBundlerMinifier som är skapat av Mads Kristensen, detta verktyg används för att minifiera statiska filer i mina projekt. Du behöver också tillägget Bundler & Minifier i Visual Studio för att kunna köra en uppgift som minifierar filer (Task Runner Explorer). När du har installerat detta paket läggs en json-fil med namnet bundleconfig.json till ditt projekt i Visual Studio. Du kan redigera den här filen direkt eller minimera statiska filer genom att högerklicka på dem i Visual Studio. Innehållet i filen bundleconfig.json ser ut ungefär så här.

[
  {
    "outputFileName": "wwwroot/css/admin_default.min.css",
    "inputFiles": [ "wwwroot/css/admin_default.css" ]
  },
  {
    "outputFileName": "wwwroot/css/admin_layout.min.css",
    "inputFiles": [ "wwwroot/css/admin_layout.css" ]
  }
]

Invalidera cacheminnet

Vi behöver en metod för att invalidera cacheminnet för statiska filer. Vi har en gemensam klass där vi har injicerat IMemoryCache och IHostingEnvironment, vi skapar en referens till en IFileProvider file_provider från environment.

public CommonServices(IMemoryCache cache, IHostingEnvironment environment)
{
    this.cache = cache;
    this.environment = environment;
    this.file_provider = environment.WebRootFileProvider;

} // End of the constructor

Vår metod för att invalidera cacheminnet lagrar den relativa sökvägen till den statiska filen och en MD5-hash för filen i minnet. Vår file_provider kommer att bevaka förändringar avseende filen och se till att filen får en ny versionsparameter.

/// <summary>
/// Get a file path with a version hash
/// </summary>
public string GetFilePath(string relative_path)
{
    // Create a variable for a hash
    string hash = "";

    // Get the hash
    if(this.cache.TryGetValue(relative_path, out hash) == false)
    {
        // Create an absolute path
        string absolute_path = this.environment.WebRootPath + relative_path;

        // Make sure that the file exists
        if(File.Exists(absolute_path) == false)
        {
            return relative_path;
        }

        // Create cache options
        MemoryCacheEntryOptions cache_entry_options = new MemoryCacheEntryOptions();

        // Add an expiration token that watches for changes in a file
        cache_entry_options.AddExpirationToken(this.file_provider.Watch(relative_path));
                
        // Create a hash of the file
        using (MD5 md5 = MD5.Create())
        {
            using (Stream stream = File.OpenRead(absolute_path))
            {
                hash = Convert.ToBase64String(md5.ComputeHash(stream));
            }
        }

        // Insert the hash to cache
        this.cache.Set(relative_path, hash, cache_entry_options);
    }

    // Return the url
    return $"{relative_path}?v={hash}";

} // End of the GetFilePath method

Lägg till referenser till statiska filer

Vi använder vår GetFilePath-metod när vi lägger till referenser till statiska filer i vår layoutvy, för bilder kan det vara bättre att använda en tidsstämpel som versionsparameter om bildernas namn inte är unika. Bilder kan vara stora och många, spara tidstämpeln i din databas och lägg till den som en versionsparameter.

<environment names="Development">
        <link href="@this.tools.GetFilePath(imageUrls.Get("small_icon"))" rel="icon" type="image/x-icon" />
        <link href="@this.tools.GetFilePath("/css/standard_layout.css")" media="screen and (min-width:1344px)" rel="stylesheet" />
        <link href="@this.tools.GetFilePath("/css/medium_layout.css")" media="only screen and (min-width:1024px) and (max-width:1343px)" rel="stylesheet" />
    </environment>
    <environment names="Staging,Production">
        <link href="@this.tools.GetFilePath(imageUrls.Get("small_icon"))" rel="icon" type="image/x-icon" />
        <link href="@this.tools.GetFilePath("/css/standard_layout.min.css")" media="screen and (min-width:1344px)" rel="stylesheet" />
        <link href="@this.tools.GetFilePath("/css/medium_layout.min.css")" media="only screen and (min-width:1024px) and (max-width:1343px)" rel="stylesheet" />
    </environment>

Tjänster

Vi måste lägga till en tjänst för minnescache i metoden ConfigureServices i klassen StartUp för att kunna cacha relativa sökvägar och en MD5-hash.

// Add memory cache
services.AddDistributedMemoryCache();

Vi måste också lägga till headers till statiska filer som visar att de kan cachas av en webbläsare och hur länge de kan cachas. Vi lägger till detta i metoden Configure i klassen StartUp.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Use static files
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // Cache static files for 30 days
            ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
            ctx.Context.Response.Headers.Append("Expires", DateTime.UtcNow.AddDays(30).ToString("R", CultureInfo.InvariantCulture));
        }
    });

    // More code ...
    
} // End of the Configure method

Du kan inspektera headers för statiska filer i Chrome under Nätverk i utvecklarverktyget för att kontrollera att de har korrekta värden.

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *