Megosztás a következőn keresztül:


Köztes szoftver kimeneti gyorsítótárazása a ASP.NET Core-ban

Készítette: Tom Dykstra

Megjegyzés:

Ez nem a cikk legújabb verziója. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .

Figyelmeztetés

A ASP.NET Core ezen verziója már nem támogatott. További információt a .NET és a .NET Core támogatási szabályzatában talál. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .

Fontos

Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.

A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .

Ez a cikk bemutatja, hogyan konfigurálhatja a kimeneti gyorsítótárazási köztes szoftvereket egy ASP.NET Core-alkalmazásban. A kimeneti gyorsítótárazásról a Kimeneti gyorsítótárazás című témakörben olvashat bővebben.

A kimeneti gyorsítótárazási köztes szoftver az ASP.NET Core-alkalmazások minden típusában használható: Minimal API, Web API vezérlőkkel, MVC és Razor Pages. A kód példákat biztosít a minimális API-khoz és a vezérlőalapú API-khoz. A vezérlőalapú API-példák bemutatják, hogyan használhatók attribútumok a gyorsítótárazás konfigurálásához. Ezek az attribútumok MVC- és Razor Pages-alkalmazásokban is használhatók.

A kódpéldák egy Gravatar-osztályra vonatkoznak, amely létrehoz egy képet, és időbélyeget ad meg a létrehozás dátuma és időpontja vonatkozásában. Az osztály definiálva van, és csak a mintaalkalmazásban használatos. Célja, hogy könnyen látható legyen, amikor a gyorsítótárazott kimenetet használják. A további információt lásd: Hogyan töltsünk le mintát és Preprocesszor-irányelvek a mintakódban.

Köztes szoftver hozzáadása az alkalmazáshoz

Adja hozzá a kimeneti gyorsítótárazási middleware-t a szolgáltatásgyűjteményhez a AddOutputCache hívásával.

Adja hozzá a köztes szoftvert a kérésfeldolgozó folyamathoz hívással UseOutputCache.

Például:

builder.Services.AddOutputCache();
var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseOutputCache();
app.UseAuthorization();

A AddOutputCacheés UseOutputCache hívása nem indítja el a gyorsítótárazási viselkedést, hanem elérhetővé teszi a gyorsítótárazást. Az alkalmazásgyorsítótár-válaszok létrehozásához a gyorsítótárazást az alábbi szakaszokban látható módon kell konfigurálni.

Megjegyzés:

  • A CORS köztes szoftvereket használó alkalmazásokban a UseOutputCache függvényt a UseCors után kell meghívni.
  • A Pages alkalmazásokban és a vezérlőkkel rendelkező alkalmazásokban a Razor meghívását a UseOutputCache után kell elvégezni.

Egy végpont vagy lap konfigurálása

Minimális API-alkalmazások esetén konfiguráljon egy végpontot gyorsítótárazásra a CacheOutput hívásával vagy az [OutputCache] attribútum alkalmazásával, ahogy az alábbi példák mutatják.

app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) => 
    Gravatar.WriteGravatar(context));

Vezérlőkkel rendelkező alkalmazások esetén alkalmazza az [OutputCache] attribútumot a műveletmetódusra az itt látható módon:

[ApiController]
[Route("/[controller]")]
[OutputCache]
public class CachedController : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

A Razor Pages alkalmazások esetében alkalmazza az attribútumot az Razor oldal osztályára.

Több végpont vagy lap konfigurálása

Hozzon létre szabályzatokat, amelyek híváskor több végpontra vonatkozó gyorsítótárazási konfigurációt adnak megAddOutputCache. A szabályzatok kiválaszthatók adott végpontokhoz, míg az alapszabályzatok alapértelmezett gyorsítótárazási konfigurációt biztosítanak a végpontok gyűjteményéhez.

Az alábbi kiemelt kód az alkalmazás összes végpontjának gyorsítótárazását konfigurálja 10 másodperces lejárati idővel. Ha nincs megadva lejárati idő, az alapértelmezés szerint egy perc.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => 
        builder.Expire(TimeSpan.FromSeconds(10)));
    options.AddPolicy("Expire20", builder => 
        builder.Expire(TimeSpan.FromSeconds(20)));
    options.AddPolicy("Expire30", builder => 
        builder.Expire(TimeSpan.FromSeconds(30)));
});

Az alábbi kiemelt kód két szabályzatot hoz létre, amelyek mindegyike eltérő lejárati időt ad meg. A kijelölt végpontok használhatják a 20 másodperces lejáratot, mások pedig a 30 másodperces lejáratot.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => 
        builder.Expire(TimeSpan.FromSeconds(10)));
    options.AddPolicy("Expire20", builder => 
        builder.Expire(TimeSpan.FromSeconds(20)));
    options.AddPolicy("Expire30", builder => 
        builder.Expire(TimeSpan.FromSeconds(30)));
});

A végpont számára szabályzatot választhat a CacheOutput metódus meghívásakor vagy a [OutputCache] attribútum használatakor.

Egy minimális API-alkalmazásban az alábbi kód egy végpontot konfigurál 20 másodperces lejárattal, egyet pedig 30 másodperces lejárattal:

app.MapGet("/20", Gravatar.WriteGravatar).CacheOutput("Expire20");
app.MapGet("/30", [OutputCache(PolicyName = "Expire30")] (context) => 
    Gravatar.WriteGravatar(context));

Vezérlőkkel rendelkező alkalmazások esetén alkalmazza az [OutputCache] attribútumot a műveletmetódusra egy szabályzat kiválasztásához:

[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "Expire20")]
public class Expire20Controller : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

A Razor Pages alkalmazások esetében alkalmazza az attribútumot az Razor oldal osztályára.

Alapértelmezett kimeneti gyorsítótárazási szabályzat

Alapértelmezés szerint a kimeneti gyorsítótárazás a következő szabályokat követi:

  • A rendszer csak a HTTP 200-válaszokat gyorsítótárazza.
  • Csak a HTTP GET vagy a HEAD kérések gyorsítótárazva vannak.
  • Olyan válaszok, amelyek cookie-kat állítanak be, nem kerülnek gyorsítótárazásra.
  • A hitelesített kérelmekre adott válaszok nem gyorsítótárazva lesznek.

Az alábbi kód az összes alapértelmezett gyorsítótárazási szabályt alkalmazza az alkalmazás összes végpontjára:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder.Cache());
});

Az alapértelmezett szabályzat felülbírálása

Az alábbi kód bemutatja, hogyan bírálhatja felül az alapértelmezett szabályokat. Az alábbi egyéni szabályzatkód kiemelt sorai lehetővé teszik a HTTP POST metódusok és a HTTP 301-válaszok gyorsítótárazását:

using Microsoft.AspNetCore.OutputCaching;
using Microsoft.Extensions.Primitives;

namespace OCMinimal;

public sealed class MyCustomPolicy : IOutputCachePolicy
{
    public static readonly MyCustomPolicy Instance = new();

    private MyCustomPolicy()
    {
    }

    ValueTask IOutputCachePolicy.CacheRequestAsync(
        OutputCacheContext context, 
        CancellationToken cancellationToken)
    {
        var attemptOutputCaching = AttemptOutputCaching(context);
        context.EnableOutputCaching = true;
        context.AllowCacheLookup = attemptOutputCaching;
        context.AllowCacheStorage = attemptOutputCaching;
        context.AllowLocking = true;

        // Vary by any query by default
        context.CacheVaryByRules.QueryKeys = "*";

        return ValueTask.CompletedTask;
    }

    ValueTask IOutputCachePolicy.ServeFromCacheAsync
        (OutputCacheContext context, CancellationToken cancellationToken)
    {
        return ValueTask.CompletedTask;
    }

    ValueTask IOutputCachePolicy.ServeResponseAsync
        (OutputCacheContext context, CancellationToken cancellationToken)
    {
        var response = context.HttpContext.Response;

        // Verify existence of cookie headers
        if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie))
        {
            context.AllowCacheStorage = false;
            return ValueTask.CompletedTask;
        }

        // Check response code
        if (response.StatusCode != StatusCodes.Status200OK && 
            response.StatusCode != StatusCodes.Status301MovedPermanently)
        {
            context.AllowCacheStorage = false;
            return ValueTask.CompletedTask;
        }

        return ValueTask.CompletedTask;
    }

    private static bool AttemptOutputCaching(OutputCacheContext context)
    {
        // Check if the current request fulfills the requirements
        // to be cached
        var request = context.HttpContext.Request;

        // Verify the method
        if (!HttpMethods.IsGet(request.Method) && 
            !HttpMethods.IsHead(request.Method) && 
            !HttpMethods.IsPost(request.Method))
        {
            return false;
        }

        // Verify existence of authorization headers
        if (!StringValues.IsNullOrEmpty(request.Headers.Authorization) || 
            request.HttpContext.User?.Identity?.IsAuthenticated == true)
        {
            return false;
        }

        return true;
    }
}

Az egyéni szabályzat használatához hozzon létre egy nevesített szabályzatot:

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("CachePost", MyCustomPolicy.Instance);
});

Válassza ki a végpont nevesített szabályzatát. A következő kód kiválasztja egy végpont egyéni szabályzatát egy minimális API-alkalmazásban:

app.MapPost("/cachedpost", Gravatar.WriteGravatar)
    .CacheOutput("CachePost");

A vezérlőművelet esetében a következő kód ugyanezt teszi:

[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "CachePost")]
public class PostController : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

Alternatív alapértelmezett szabályzat felülbírálása

Alternatívaként használja a Függőséginjektálást (DI) egy példány inicializálásához, a következő módosításokkal az egyéni házirend osztályában:

  • Magánkonstruktor helyett nyilvános konstruktor.
  • Törölje a tulajdonságot Instance az egyéni szabályzatosztályból.

Például:

public sealed class MyCustomPolicy2 : IOutputCachePolicy
{

    public MyCustomPolicy2()
    {
    }

Az osztály többi része megegyezik a korábban láthatóval. Adja hozzá az egyéni szabályzatot az alábbi példában látható módon:

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("CachePost", builder => 
        builder.AddPolicy<MyCustomPolicy2>(), true);
});

Az előző kód a DI használatával hozza létre az egyéni szabályzatosztály példányát. A konstruktorban lévő nyilvános argumentumok feloldódnak.

Ha egyéni szabályzatot használ alapszabályzatként, ne hívjon meg OutputCache() (argumentumok nélkül), és ne használja az [OutputCache] attribútumot olyan végponton, amelyre az alapházirendnek vonatkoznia kell. Az attribútum meghívása OutputCache() vagy használata hozzáadja az alapértelmezett szabályzatot a végponthoz.

A gyorsítótárkulcs megadása

Alapértelmezés szerint az URL-cím minden része a gyorsítótár-bejegyzés kulcsává válik, azaz a séma, a gazdagép, a port, az elérési út és a lekérdezési sztring. Előfordulhat azonban, hogy explicit módon szeretné szabályozni a gyorsítótárkulcsot. Tegyük fel például, hogy van egy végpontja, amely csak a culture lekérdezési sztring minden egyedi értékére ad vissza egyedi választ. Az URL más részeinek, például más lekérdezési sztringeknek a variációja nem eredményezhet különböző gyorsítótár-bejegyzéseket. Ezeket a szabályokat megadhatja egy szabályzatban, ahogyan az a következő kiemelt kódban is látható:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Ezután kiválaszthatja a VaryByQuery végponthoz tartozó szabályzatot. Egy minimális API-alkalmazásban az alábbi kód kiválasztja egy VaryByQuery végpont szabályzatát, amely csak a culture lekérdezési sztring minden egyedi értékére ad vissza egyedi választ:

app.MapGet("/query", Gravatar.WriteGravatar).CacheOutput("Query");

A vezérlőművelet esetében a következő kód ugyanezt teszi:

[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "Query")]
public class QueryController : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

Íme néhány lehetőség a gyorsítótárkulcs vezérlésére:

  • SetVaryByQuery – Adjon meg egy vagy több lekérdezési sztringnevet, amely hozzáadható a gyorsítótárkulcshoz.

  • SetVaryByHeader – Adjon meg egy vagy több HTTP-fejlécet, amely hozzáadható a gyorsítótárkulcshoz.

  • VaryByValue– Adja meg a gyorsítótárkulcshoz hozzáadni kívánt értéket. Az alábbi példa egy értéket használ, amely azt jelzi, hogy a kiszolgáló aktuális ideje másodpercben páratlan vagy páros. Új válasz csak akkor jön létre, ha a másodpercek száma páratlanról párosra vagy párosra megy.

    builder.Services.AddOutputCache(options =>
    {
        options.AddBasePolicy(builder => builder
            .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
            .Tag("tag-blog"));
        options.AddBasePolicy(builder => builder.Tag("tag-all"));
        options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
        options.AddPolicy("NoCache", builder => builder.NoCache());
        options.AddPolicy("NoLock", builder => builder.SetLocking(false));
        options.AddPolicy("VaryByValue", builder => 
            builder.VaryByValue((context) =>
                new KeyValuePair<string, string>(
                "time", (DateTime.Now.Second % 2)
                    .ToString(CultureInfo.InvariantCulture))));
    });
    

A OutputCacheOptions.UseCaseSensitivePaths használatával megadhatja, hogy a kulcs elérési útja kis- és nagybetű érzékeny. Az alapértelmezett érzéketlen a kis- és nagybetűkre.

További lehetőségekért tekintse meg az OutputCachePolicyBuilder osztályt.

Gyorsítótár-újraértékelés

A gyorsítótár-újraértékelés azt jelenti, hogy a kiszolgáló a teljes válasz törzse helyett EGY HTTP-állapotkódot tud visszaadni 304 Not Modified . Ez az állapotkód tájékoztatja az ügyfelet, hogy a kérésre adott válasz nem változik, mint amit az ügyfél korábban kapott.

Az alábbi kód egy Etag fejléc használatát mutatja be a gyorsítótár újraértékelésének engedélyezéséhez. Ha az ügyfél egy korábbi válasz etagértékével küld egy If-None-Match fejlécet, és a gyorsítótár-bejegyzés friss, a kiszolgáló a teljes válasz helyett a 304 Nem módosítva értéket adja vissza. Az alábbi módon állíthatja be az etag értéket egy szabályzatban egy Minimális API-alkalmazásban:

app.MapGet("/etag", async (context) =>
{
    var etag = $"\"{Guid.NewGuid():n}\"";
    context.Response.Headers.ETag = etag;
    await Gravatar.WriteGravatar(context);

}).CacheOutput();

A következő módon állíthatja be az etag értékét egy vezérlőalapú API-ban:

[ApiController]
[Route("/[controller]")]
[OutputCache]
public class EtagController : ControllerBase
{
    public async Task GetAsync()
    {
        var etag = $"\"{Guid.NewGuid():n}\"";
        HttpContext.Response.Headers.ETag = etag;
        await Gravatar.WriteGravatar(HttpContext);
    }
}

A gyorsítótár-újraértékelés másik módja az, hogy összehasonlítjuk a gyorsítótár-bejegyzés létrehozásának dátumát az ügyfél által kért dátummal. A kérelem fejlécének If-Modified-Since megadásakor a kimeneti gyorsítótárazás 304-et ad vissza, ha a gyorsítótárazott bejegyzés régebbi, és nem járt le.

A gyorsítótár újraértékelése automatikusan történik az ügyféltől érkező fejlécek hatására. Ennek a viselkedésnek az engedélyezéséhez nincs szükség speciális konfigurációra a kiszolgálón, a kimeneti gyorsítótárazás engedélyezésén kívül.

Gyorsítótár bejegyzések eltávolítása címkék használatával

Címkék használatával azonosíthatja a végpontok egy csoportját, és kizárhatja a csoport összes gyorsítótár-bejegyzését. Az alábbi minimális API-kód például létrehoz egy olyan végpontpárt, amelynek URL-címei "blog"-tal kezdődnek, és címkézik a "tag-blog" címkét:

app.MapGet("/blog", Gravatar.WriteGravatar)
    .CacheOutput(builder => builder.Tag("tag-blog"));
app.MapGet("/blog/post/{id}", Gravatar.WriteGravatar)
    .CacheOutput(builder => builder.Tag("tag-blog"));

Az alábbi kód bemutatja, hogyan rendelhet címkéket egy végponthoz egy vezérlőalapú API-ban:

[ApiController]
[Route("/[controller]")]
[OutputCache(Tags = new[] { "tag-blog", "tag-all" })]
public class TagEndpointController : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

A kezdő útvonalakkal blog rendelkező végpontok címkéinek hozzárendelésének másik módja egy olyan alapházirend meghatározása, amely az adott útvonallal rendelkező összes végpontra érvényes. A következő kód bemutatja, hogyan teheti ezt meg:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

A minimális API-alkalmazások esetében az egyik alternatíva a(z) MapGroup hívása:

var blog = app.MapGroup("blog")
    .CacheOutput(builder => builder.Tag("tag-blog"));
blog.MapGet("/", Gravatar.WriteGravatar);
blog.MapGet("/post/{id}", Gravatar.WriteGravatar);

Az előző címke-hozzárendelési példákban mindkét végpontot azonosítja a tag-blog címke. Ezután az adott címkére hivatkozó egyetlen utasítással kiürítheti a végpontok gyorsítótár-bejegyzéseit:

app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag) =>
{
    await cache.EvictByTagAsync(tag, default);
});

Ezzel a kóddal egy HTTP POST-kérés elküldése https://localhost:<port>/purge/tag-blog a végpontok gyorsítótár-bejegyzéseinek kiürítésére szolgál.

Érdemes lehet az összes végpont összes gyorsítótárbejegyzését kiüríteni. Ehhez hozza létre az összes végponthoz egy alapházirendet, az alábbi kód szerint.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Ez az alapszabályzat lehetővé teszi, hogy a "tag-all" címkével kiürítsen mindent a gyorsítótárból.

Erőforrás-zárolás letiltása

Alapértelmezés szerint az erőforrás-zárolás engedélyezve van a gyorsítótárbélyegzés és a villámgyors csorda kockázatának csökkentése érdekében. További információ: Kimeneti gyorsítótárazás.

Az erőforrás-zárolás letiltásához hívja meg a SetLocking(false) függvényt egy szabályzat létrehozásakor, ahogyan az alábbi példában látható:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Az alábbi példa egy minimális API-alkalmazás végpontjánál a zárolás nélküli szabályzatot választja:

app.MapGet("/nolock", Gravatar.WriteGravatar)
    .CacheOutput("NoLock");

Egy vezérlőalapú API-ban az attribútum használatával válassza ki a szabályzatot:

[ApiController]
[Route("/[controller]")]
[OutputCache(PolicyName = "NoLock")]
public class NoLockController : ControllerBase
{
    public async Task GetAsync()
    {
        await Gravatar.WriteGravatar(HttpContext);
    }
}

Korlátok

Az alábbi tulajdonságok OutputCacheOptions lehetővé teszik az összes végpontra vonatkozó korlátok konfigurálását:

  • SizeLimit - A gyorsítótár tárterületének maximális mérete. Ha eléri ezt a korlátot, a rendszer nem gyorsítótárazza az új válaszokat, amíg a régebbi bejegyzések ki nem kerülnek. Az alapértelmezett érték 100 MB.
  • MaximumBodySize - Ha a válasz törzse túllépi ezt a korlátot, nem kerül gyorsítótárazásra. Az alapértelmezett érték 64 MB.
  • DefaultExpirationTimeSpan – A szabályzat által nem megadott lejárati idő. Az alapértelmezett érték 60 másodperc.

Gyorsítótár-tároló

IOutputCacheStore tárolásra szolgál. Alapértelmezés szerint a következővel használják: MemoryCache. A gyorsítótárazott válaszok tárolása folyamatban történik, így minden kiszolgáló külön gyorsítótárral rendelkezik, amely a kiszolgálói folyamat újraindításakor elveszik.

Redis Cache

Másik lehetőség a Redis Cache használata. A Redis Cache konzisztenciát biztosít a kiszolgálócsomópontok között egy megosztott gyorsítótáron keresztül, amely túllépi az egyes kiszolgálói folyamatokat. Redis használata kimeneti gyorsítótárként:

  • Telepítse a Microsoft.AspNetCore.OutputCaching.StackExchangeRedis NuGet csomagot.

  • Hívja meg builder.Services.AddStackExchangeRedisOutputCache (nem AddStackExchangeRedisCache), és adjon meg egy Redis-kiszolgálóra mutató kapcsolati sztringet.

    Például:

    builder.Services.AddStackExchangeRedisOutputCache(options =>
    {
        options.Configuration = 
            builder.Configuration.GetConnectionString("MyRedisConStr");
        options.InstanceName = "SampleInstance";
    });
    
    builder.Services.AddOutputCache(options =>
    {
        options.AddBasePolicy(builder => 
            builder.Expire(TimeSpan.FromSeconds(10)));
    });
    
    • options.Configuration - Kapcsolati lánc egy helyszíni Redis-kiszolgálóhoz vagy egy üzemeltetett ajánlathoz, például az Azure Cache for Redishez. Például az Azure Cache for Redis esetében <instance_name>.redis.cache.windows.net:6380,password=,pw,ssl=True,abortConnect=False.
    • options.InstanceName – Nem kötelező, egy logikai partíciót ad meg a gyorsítótárhoz.

    A konfigurációs beállítások megegyeznek a Redis-alapú elosztott gyorsítótárazási lehetőségekkel.

Nem javasoljuk IDistributedCache kimeneti gyorsítótárazással való használatát. IDistributedCache nem rendelkezik atomi jellemzőkkel, amelyek a címkézéshez szükségesek. Javasoljuk, hogy használja a Redis beépített támogatását, vagy hozzon létre egyéni IOutputCacheStore implementációkat a mögöttes tárolási mechanizmus közvetlen függőségeinek használatával.

Lásd még

Ez a cikk bemutatja, hogyan konfigurálhatja a kimeneti gyorsítótárazási köztes szoftvereket egy ASP.NET Core-alkalmazásban. A kimeneti gyorsítótárazásról a Kimeneti gyorsítótárazás című témakörben olvashat bővebben.

A kimeneti gyorsítótárazási köztes szoftver az ASP.NET Core-alkalmazások minden típusában használható: Minimal API, Web API vezérlőkkel, MVC és Razor Pages. A mintaalkalmazás egy minimális API, de a többi alkalmazástípus is támogatja az általa illusztrált gyorsítótárazási funkciókat.

Köztes szoftver hozzáadása az alkalmazáshoz

Adja hozzá a kimeneti gyorsítótárazási middleware-t a szolgáltatásgyűjteményhez a AddOutputCache hívásával.

Adja hozzá a köztes szoftvert a kérésfeldolgozó folyamathoz hívással UseOutputCache.

Megjegyzés:

  • A CORS köztes szoftvereket használó alkalmazásokban a UseOutputCache függvényt a UseCors után kell meghívni.
  • A Pages alkalmazásokban és a vezérlőkkel rendelkező alkalmazásokban a Razor meghívását a UseOutputCache után kell elvégezni.
  • A AddOutputCacheés UseOutputCache hívása nem indítja el a gyorsítótárazási viselkedést, hanem elérhetővé teszi a gyorsítótárazást. A gyorsítótárazási válaszadatokat az alábbi szakaszokban látható módon kell konfigurálni.

Egy végpont vagy lap konfigurálása

Minimális API-alkalmazások esetén konfiguráljon egy végpontot gyorsítótárazásra a CacheOutput hívásával vagy az [OutputCache] attribútum alkalmazásával, ahogy az alábbi példák mutatják.

app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) => 
    Gravatar.WriteGravatar(context));

Vezérlőkkel rendelkező alkalmazások esetén alkalmazza a [OutputCache] attribútumot a műveletmetódusra. A Razor Pages alkalmazások esetében alkalmazza az attribútumot az Razor oldal osztályára.

Több végpont vagy lap konfigurálása

Hozzon létre szabályzatokat, amelyek híváskor több végpontra vonatkozó gyorsítótárazási konfigurációt adnak megAddOutputCache. A szabályzatok kiválaszthatók adott végpontokhoz, míg az alapszabályzatok alapértelmezett gyorsítótárazási konfigurációt biztosítanak a végpontok gyűjteményéhez.

Az alábbi kiemelt kód az alkalmazás összes végpontjának gyorsítótárazását konfigurálja 10 másodperces lejárati idővel. Ha nincs megadva lejárati idő, az alapértelmezés szerint egy perc.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => 
        builder.Expire(TimeSpan.FromSeconds(10)));
    options.AddPolicy("Expire20", builder => 
        builder.Expire(TimeSpan.FromSeconds(20)));
    options.AddPolicy("Expire30", builder => 
        builder.Expire(TimeSpan.FromSeconds(30)));
});

Az alábbi kiemelt kód két szabályzatot hoz létre, amelyek mindegyike eltérő lejárati időt ad meg. A kijelölt végpontok használhatják a 20 másodperces lejáratot, mások pedig a 30 másodperces lejáratot.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => 
        builder.Expire(TimeSpan.FromSeconds(10)));
    options.AddPolicy("Expire20", builder => 
        builder.Expire(TimeSpan.FromSeconds(20)));
    options.AddPolicy("Expire30", builder => 
        builder.Expire(TimeSpan.FromSeconds(30)));
});

A metódus meghívásakor CacheOutput vagy az [OutputCache] attribútum használatakor kiválaszthatja a végponthoz tartozó szabályzatot:

app.MapGet("/20", Gravatar.WriteGravatar).CacheOutput("Expire20");
app.MapGet("/30", [OutputCache(PolicyName = "Expire30")] (context) => 
    Gravatar.WriteGravatar(context));

Vezérlőkkel rendelkező alkalmazások esetén alkalmazza a [OutputCache] attribútumot a műveletmetódusra. A Razor Pages alkalmazások esetében alkalmazza az attribútumot az Razor oldal osztályára.

Alapértelmezett kimeneti gyorsítótárazási szabályzat

Alapértelmezés szerint a kimeneti gyorsítótárazás a következő szabályokat követi:

  • A rendszer csak a HTTP 200-válaszokat gyorsítótárazza.
  • Csak a HTTP GET vagy a HEAD kérések gyorsítótárazva vannak.
  • Olyan válaszok, amelyek cookie-kat állítanak be, nem kerülnek gyorsítótárazásra.
  • A hitelesített kérelmekre adott válaszok nem gyorsítótárazva lesznek.

Az alábbi kód az összes alapértelmezett gyorsítótárazási szabályt alkalmazza az alkalmazás összes végpontjára:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder.Cache());
});

Az alapértelmezett szabályzat felülbírálása

Az alábbi kód bemutatja, hogyan bírálhatja felül az alapértelmezett szabályokat. Az alábbi egyéni szabályzatkód kiemelt sorai lehetővé teszik a HTTP POST metódusok és a HTTP 301-válaszok gyorsítótárazását:

using Microsoft.AspNetCore.OutputCaching;
using Microsoft.Extensions.Primitives;

namespace OCMinimal;

public sealed class MyCustomPolicy : IOutputCachePolicy
{
    public static readonly MyCustomPolicy Instance = new();

    private MyCustomPolicy()
    {
    }

    ValueTask IOutputCachePolicy.CacheRequestAsync(
        OutputCacheContext context, 
        CancellationToken cancellationToken)
    {
        var attemptOutputCaching = AttemptOutputCaching(context);
        context.EnableOutputCaching = true;
        context.AllowCacheLookup = attemptOutputCaching;
        context.AllowCacheStorage = attemptOutputCaching;
        context.AllowLocking = true;

        // Vary by any query by default
        context.CacheVaryByRules.QueryKeys = "*";

        return ValueTask.CompletedTask;
    }

    ValueTask IOutputCachePolicy.ServeFromCacheAsync
        (OutputCacheContext context, CancellationToken cancellationToken)
    {
        return ValueTask.CompletedTask;
    }

    ValueTask IOutputCachePolicy.ServeResponseAsync
        (OutputCacheContext context, CancellationToken cancellationToken)
    {
        var response = context.HttpContext.Response;

        // Verify existence of cookie headers
        if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie))
        {
            context.AllowCacheStorage = false;
            return ValueTask.CompletedTask;
        }

        // Check response code
        if (response.StatusCode != StatusCodes.Status200OK && 
            response.StatusCode != StatusCodes.Status301MovedPermanently)
        {
            context.AllowCacheStorage = false;
            return ValueTask.CompletedTask;
        }

        return ValueTask.CompletedTask;
    }

    private static bool AttemptOutputCaching(OutputCacheContext context)
    {
        // Check if the current request fulfills the requirements
        // to be cached
        var request = context.HttpContext.Request;

        // Verify the method
        if (!HttpMethods.IsGet(request.Method) && 
            !HttpMethods.IsHead(request.Method) && 
            !HttpMethods.IsPost(request.Method))
        {
            return false;
        }

        // Verify existence of authorization headers
        if (!StringValues.IsNullOrEmpty(request.Headers.Authorization) || 
            request.HttpContext.User?.Identity?.IsAuthenticated == true)
        {
            return false;
        }

        return true;
    }
}

Az egyéni szabályzat használatához hozzon létre egy nevesített szabályzatot:

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("CachePost", MyCustomPolicy.Instance);
});

És válassza ki a megnevezett szabályzatot a végponthoz:

app.MapPost("/cachedpost", Gravatar.WriteGravatar)
    .CacheOutput("CachePost");

Alternatív alapértelmezett szabályzat felülbírálása

Alternatívaként használja a Függőséginjektálást (DI) egy példány inicializálásához, a következő módosításokkal az egyéni házirend osztályában:

  • Magánkonstruktor helyett nyilvános konstruktor.
  • Törölje a tulajdonságot Instance az egyéni szabályzatosztályból.

Például:

public sealed class MyCustomPolicy2 : IOutputCachePolicy
{

    public MyCustomPolicy2()
    {
    }

Az osztály többi része megegyezik a korábban láthatóval. Adja hozzá az egyéni szabályzatot az alábbi példában látható módon:

builder.Services.AddOutputCache(options =>
{
    options.AddPolicy("CachePost", builder => 
        builder.AddPolicy<MyCustomPolicy2>(), true);
});

Az előző kód a DI használatával hozza létre az egyéni szabályzatosztály példányát. A konstruktorban lévő nyilvános argumentumok feloldódnak.

Ha egyéni szabályzatot használ alapházirendként, ne hívjon OutputCache() meg (argumentumok nélkül) olyan végpontot, amelyre az alapházirendnek vonatkoznia kell. A hívás OutputCache() hozzáadja az alapértelmezett szabályzatot a végponthoz.

A gyorsítótárkulcs megadása

Alapértelmezés szerint az URL-cím minden része a gyorsítótár-bejegyzés kulcsává válik, azaz a séma, a gazdagép, a port, az elérési út és a lekérdezési sztring. Előfordulhat azonban, hogy explicit módon szeretné szabályozni a gyorsítótárkulcsot. Tegyük fel például, hogy van egy végpontja, amely csak a culture lekérdezési sztring minden egyedi értékére ad vissza egyedi választ. Az URL más részeinek, például más lekérdezési sztringeknek a variációja nem eredményezhet különböző gyorsítótár-bejegyzéseket. Ezeket a szabályokat megadhatja egy szabályzatban, ahogyan az a következő kiemelt kódban is látható:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Ezután kiválaszthatja a VaryByQuery szabályzatot a végponthoz.

app.MapGet("/query", Gravatar.WriteGravatar).CacheOutput("Query");

Íme néhány lehetőség a gyorsítótárkulcs vezérlésére:

  • SetVaryByQuery – Adjon meg egy vagy több lekérdezési sztringnevet, amely hozzáadható a gyorsítótárkulcshoz.

  • SetVaryByHeader – Adjon meg egy vagy több HTTP-fejlécet, amely hozzáadható a gyorsítótárkulcshoz.

  • VaryByValue– Adja meg a gyorsítótárkulcshoz hozzáadni kívánt értéket. Az alábbi példa egy értéket használ, amely azt jelzi, hogy a kiszolgáló aktuális ideje másodpercben páratlan vagy páros. Új válasz csak akkor jön létre, ha a másodpercek száma páratlanról párosra vagy párosra megy.

    app.MapGet("/varybyvalue", Gravatar.WriteGravatar)
        .CacheOutput(c => c.VaryByValue((context) => 
            new KeyValuePair<string, string>(
                "time", (DateTime.Now.Second % 2)
                    .ToString(CultureInfo.InvariantCulture))));
    

A OutputCacheOptions.UseCaseSensitivePaths használatával megadhatja, hogy a kulcs elérési útja kis- és nagybetű érzékeny. Az alapértelmezett érzéketlen a kis- és nagybetűkre.

További lehetőségekért tekintse meg az OutputCachePolicyBuilder osztályt.

Gyorsítótár-újraértékelés

A gyorsítótár-újraértékelés azt jelenti, hogy a kiszolgáló a teljes válasz törzse helyett EGY HTTP-állapotkódot tud visszaadni 304 Not Modified . Ez az állapotkód tájékoztatja az ügyfelet, hogy a kérésre adott válasz nem változik, mint amit az ügyfél korábban kapott.

Az alábbi kód egy Etag fejléc használatát mutatja be a gyorsítótár újraértékelésének engedélyezéséhez. Ha az ügyfél egy If-None-Match korábbi válasz etagértékével rendelkező fejlécet küld, és a gyorsítótár-bejegyzés friss, a kiszolgáló a teljes válasz helyett a 304 Nem módosult értéket adja vissza:

app.MapGet("/etag", async (context) =>
{
    var etag = $"\"{Guid.NewGuid():n}\"";
    context.Response.Headers.ETag = etag;
    await Gravatar.WriteGravatar(context);

}).CacheOutput();

A gyorsítótár-újraértékelés másik módja az, hogy összehasonlítjuk a gyorsítótár-bejegyzés létrehozásának dátumát az ügyfél által kért dátummal. A kérelem fejlécének If-Modified-Since megadásakor a kimeneti gyorsítótárazás 304-et ad vissza, ha a gyorsítótárazott bejegyzés régebbi, és nem járt le.

A gyorsítótár újraértékelése automatikusan történik az ügyféltől érkező fejlécek hatására. Ennek a viselkedésnek az engedélyezéséhez nincs szükség speciális konfigurációra a kiszolgálón, a kimeneti gyorsítótárazás engedélyezésén kívül.

Gyorsítótár bejegyzések eltávolítása címkék használatával

Címkék használatával azonosíthatja a végpontok egy csoportját, és kizárhatja a csoport összes gyorsítótár-bejegyzését. Az alábbi kód például létrehoz egy végpontpárt, amelynek URL-címei "blog"-tal kezdődnek, és címkézik őket "tag-blog":

app.MapGet("/blog", Gravatar.WriteGravatar)
    .CacheOutput(builder => builder.Tag("tag-blog"));
app.MapGet("/blog/post/{id}", Gravatar.WriteGravatar)
    .CacheOutput(builder => builder.Tag("tag-blog"));

Ugyanazon végpontpár címkéinek hozzárendelésének másik módja egy olyan alapházirend definiálása, amely a következővel blogkezdődő végpontokra vonatkozik:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Egy másik alternatíva a következő módon hívni MapGroup:

var blog = app.MapGroup("blog")
    .CacheOutput(builder => builder.Tag("tag-blog"));
blog.MapGet("/", Gravatar.WriteGravatar);
blog.MapGet("/post/{id}", Gravatar.WriteGravatar);

Az előző címke-hozzárendelési példákban mindkét végpontot azonosítja a tag-blog címke. Ezután az adott címkére hivatkozó egyetlen utasítással kiürítheti a végpontok gyorsítótár-bejegyzéseit:

app.MapPost("/purge/{tag}", async (IOutputCacheStore cache, string tag) =>
{
    await cache.EvictByTagAsync(tag, default);
});

Ezzel a kóddal, egy HTTP POST-kérés, amelyet a(z) https://localhost:<port>/purge/tag-blog címre küldünk, kiüríti a gyorsítótár bejegyzéseit ezekről a végpontokról.

Érdemes lehet az összes végpont összes gyorsítótárbejegyzését kiüríteni. Ehhez hozza létre az összes végponthoz egy alapházirendet, az alábbi kód szerint.

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Ez az alapszabályzat lehetővé teszi, hogy a "tag-all" címkével kiürítsen mindent a gyorsítótárból.

Erőforrás-zárolás letiltása

Alapértelmezés szerint az erőforrás-zárolás engedélyezve van a gyorsítótárbélyegzés és a villámgyors csorda kockázatának csökkentése érdekében. További információ: Kimeneti gyorsítótárazás.

Az erőforrás-zárolás letiltásához hívja meg a SetLocking(false) függvényt egy szabályzat létrehozásakor, ahogyan az alábbi példában látható:

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder
        .With(c => c.HttpContext.Request.Path.StartsWithSegments("/blog"))
        .Tag("tag-blog"));
    options.AddBasePolicy(builder => builder.Tag("tag-all"));
    options.AddPolicy("Query", builder => builder.SetVaryByQuery("culture"));
    options.AddPolicy("NoCache", builder => builder.NoCache());
    options.AddPolicy("NoLock", builder => builder.SetLocking(false));
});

Az alábbi példa egy végpont nem zárolási szabályzatát választja ki:

app.MapGet("/nolock", Gravatar.WriteGravatar)
    .CacheOutput("NoLock");

Korlátok

Az alábbi tulajdonságok OutputCacheOptions lehetővé teszik az összes végpontra vonatkozó korlátok konfigurálását:

  • SizeLimit - A gyorsítótár tárterületének maximális mérete. A korlát elérésekor a rendszer nem gyorsítótárazza az új válaszokat, amíg a régebbi bejegyzések ki nem kerülnek. Az alapértelmezett érték 100 MB.
  • MaximumBodySize - Ha a válasz törzse túllépi ezt a korlátot, nem kerül gyorsítótárazásra. Az alapértelmezett érték 64 MB.
  • DefaultExpirationTimeSpan – A szabályzat által nem megadott lejárati idő. Az alapértelmezett érték 60 másodperc.

Gyorsítótár-tároló

IOutputCacheStore tárolásra szolgál. Alapértelmezés szerint a következővel használják: MemoryCache. Nem javasoljuk IDistributedCache kimeneti gyorsítótárazással való használatát. IDistributedCache nem rendelkezik atomi jellemzőkkel, amelyek a címkézéshez szükségesek. Javasoljuk, hogy egyéni IOutputCacheStore implementációkat hozzon létre az alapul szolgáló tárolási mechanizmus közvetlen függőségei, például a Redis használatával. Vagy használja a Redis Cache beépített támogatását a .NET 8-ban.

Lásd még