In uno script precedente (https://www.aspitalia.com/script/1212/Misurare-Tempo-Esecuzione-Richiesta-ASP.NET-Middleware-OWIN.aspx) abbiamo realizzato un middleware in grado di misurare il tempo di elaborazione di una richiesta ASP.NET.
Il valore misurato veniva poi loggato e visualizzato in console ma immaginiamo ora di volerlo includere come intestazione della Response.
La prima soluzione che ci verrebbe in mente, consiste nell'aggiungere una voce alla collezione Response.Headers, analogamente a quanto siamo abituati a fare in un'applicazione ASP.NET tradizionale.
public override async Task Invoke(IOwinContext context) { //[Omissis] Avviamo il cronometro come da script precedente //Passiamo il controllo al middleware successivo await Next.Invoke(context); //[Omissis] Fermiamo il cronometro //Aggiungiamo l'intestazione (modo non corretto) context.Response.Headers.Add("Duration", new[] { measuredValue }); }
Purtroppo questa prima soluzione non sortirà l'effetto voluto e la nostra intestazione Duration potrebbe non apparire affatto nella Response, nonostante non venga sollevato alcun errore.
Infatti, nel momento in cui cerchiamo di aggiungere quell'intestazione, l'output della Response potrebbe essere già stato prodotto da un middleware successivo. La nostra istruzione viene dunque eseguita troppo tardi, in un momento in cui modificare la collezione Headers diventa irrilevante.
Per risolvere questa situazione, l'astrazione offerta dall'OwinMiddleware espone il metodo OnSendingHeaders per l'oggetto Response.
A OnSendingHeaders forniremo un callback che verrà invocato in un momento utile, ovvero proprio prima che le intestazioni della Response siano inviate al client. Come secondo argomento, possiamo fornire un oggetto arbitrario che ritroveremmo nella callback; in ogni modo, ciò diventa superfluo se usiamo una anonymous function e sfruttiamo il meccanismo delle closure per referenziare membri locali, come nell'esempio seguente:
public override async Task Invoke(IOwinContext context) { //Avviamo il cronometro var stopwatch = new Stopwatch(); stopwatch.Start(); //Prima di passare il controllo al middleware successivo, //impostiamo la callback che ci consentirà di //aggiungere l'intestazione al momento opportuno context.Response.OnSendingHeaders(state => { //Fermiamo il cronometro e prendiamo il tempo stopwatch.Stop(); var measuredValue = stopwatch.Elapsed.ToString(); //Aggiungiamo l'intestazione (modo corretto) context.Response.Headers.Add("Duration", new[] { measuredValue }); //Passiamo il controllo al middleware successivo //che a sua volta lo passerà al successivo await Next.Invoke(context); }
In questo modo vedremo apparire "Duration" tra le intestazioni della risposta, come ci aspettavamo.
Questa soluzione è idonea anche per manipolare la collezione Response.Headers a nostro piacimento, per esempio per rimuovere o cambiare i valori delle intestazioni impostate da altri middleware.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Ottimizzare il mapping di liste di tipi semplici con Entity Framework Core
Usare un KeyedService di default in ASP.NET Core 8
Eseguire query per recuperare il padre di un record che sfrutta il tipo HierarchyID in Entity Framework
Filtrare i dati di una QuickGrid in Blazor con una drop down list
Triggerare una pipeline su un altro repository di Azure DevOps
Gestione dei nomi con le regole @layer in CSS
Definire stili a livello di libreria in Angular
Eseguire le GitHub Actions offline
Ordinare randomicamente una lista in C#
Generare HTML a runtime a partire da un componente Razor in ASP.NET Core
Inference di dati strutturati da testo con Semantic Kernel e ASP.NET Core Web API
Eseguire script pre e post esecuzione di un workflow di GitHub