Quando un sito web sfrutta l'output cache, come abbiamo visto finora in ASP.NET Core 7, il server evita di processare la richiesta e fornisce immediatamente la stessa risposta di un'invocazione analoga avvenuta in precedenza.
Si tratta di una grande ottimizzazione per l'uso delle risorse del server, perché la risposta richiede pochissima CPU, ma c'è comunque un transito di dati sulla rete, che può avere costi a livelli di banda e anche di performance.
Una soluzione standard a questo problema è l'uso degli ETag (Entity Tag: https://www.w3.org/2005/MWI/BPWG/techs/CachingWithETag.html), ossia degli identificativi che vengono associati alla risposta del server. Cerchiamo di capire come sfruttarli in ASP.NET Core 7.
Il primo passo è quello di aggiungere l'Etag alla risposta che generiamo:
[HttpGet("demo")] public IActionResult Cached(string name) { this.HttpContext.Response.Headers.ETag = $"\"{Guid.NewGuid():n}\""; return this.Ok($"Hello, {name}, time is {DateTime.Now.ToLongTimeString()} and this is cached"); }
Il tag, come possiamo vedere, è semplicemente un Guid che generiamo randomicamente, e che verrà catturato dal middleware di OutputCache e memorizzato unitamente alla risposta.
A questo punto, immaginiamo di avere un client, per esempio un sito Blazor, in cui invochiamo l'endpoint in alto:
<button class="btn btn-primary" @onclick="FetchDataAsync">Click me</button> <p>@apiResponse</p> @code { private string apiResponse = "No response"; private async Task FetchDataAsync() { apiResponse = await Http.GetStringAsync( "https://localhost:7088/api/cache/demo?name=Marco"); } }
Come possiamo notare, si tratta di una normalissima richiesta tramite HttpClient, senza alcuna logica di cache.
Quando il browser esegue la richiesta per la prima volta, riceve l'ETag che verrà memorizzato nella sua local cache, unitamente al contenuto della risposta.
HTTP/2 200 OK content-type: text/plain; charset=utf-8 date: Sun, 05 Mar 2023 11:59:40 GMT server: Kestrel access-control-allow-origin: * etag: "9360fbd21d0d4ec9919a0a0dcd2ba0b9"
A una successiva richiesta, invierà lo stesso ETag in un header If-None-Match, come nel trace in basso:
GET /api/cache/demo?name=Marco HTTP/2 Host: localhost:7088 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.0 Accept: */* Accept-Language: en-GB,en;q=0.5 ... If-None-Match: "9360fbd21d0d4ec9919a0a0dcd2ba0b9"
A questo punto, entra in gioco nuovamente il middleware di OutputCache in ASP.NET Core 7, che confronta questo header con l'ETag in cache, rispondendo con uno status code 304 Not Modified in caso di match, senza inviare alcun contenuto.
HTTP/2 304 Not Modified date: Sun, 05 Mar 2023 11:59:40 GMT server: Kestrel access-control-allow-origin: * etag: "9360fbd21d0d4ec9919a0a0dcd2ba0b9" X-Firefox-Spdy: h2
Il risultato serve a segnalare al browser che la sua cache locale è ancora valida, e può essere utilizzata come valore della risposta. La chiamata pertanto avrà una durata pressoché istantanea, come possiamo notare dall'immagine in basso.
Allo scadere della cache sul server, invece, il middleware di OutputCache non riconoscerà più l'ETag inviato dal browser, e risponderà con un 200 OK inviando anche il contenuto della risposta.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Sfruttare i KeyedService in un'applicazione Blazor in .NET 8
Inference di dati strutturati da testo con Semantic Kernel e ASP.NET Core Web API
Registrare servizi multipli tramite chiavi in ASP.NET Core 8
Eseguire query manipolando liste di tipi semplici con Entity Framework Core
Generare HTML a runtime a partire da un componente Razor in ASP.NET Core
Migrare una service connection a workload identity federation in Azure DevOps
Miglioramenti nell'accessibilità con Angular CDK
Come EF 8 ha ottimizzato le query che usano il metodo Contains
Migliorare la sicurezza dei prompt con Azure AI Studio
Potenziare Azure AI Search con la ricerca vettoriale
Disabilitare automaticamente un workflow di GitHub (parte 2)
Eseguire un metodo asincrono dopo il set di una proprietà in Blazor 8