Quando sviluppiamo applicazioni web è importante che i tempi di caricamento siano ridotti al minimo, in modo che i nostri utenti abbiano una migliore percezione della qualità del nostro servizio.
Il protocollo HTTP prevede che i dati che inviamo al client possano essere compressi, in modo da ridurre la durata di ciascun trasferimento dati.
Se la nostra applicazione è ospitata nel webserver IIS, possiamo abilitare (o disabilitare) la compressione agendo sul nodo system.webServer/urlCompression del web.config.
<system.webServer> <urlCompression doStaticCompression="true" doDynamicCompression="false" /> </system.webServer>
Tuttavia, un'applicazione ASP.NET Core può essere ospitata anche da altri webserver. Nelle situazioni in cui non possiamo (o non vogliamo) affidarci ad IIS, ha senso che la compressione sia svolta dall'applicazione stessa per avere un comportamento uniforme e indipendente dalla piattaforma di hosting.
Aggiungere il middleware di compressione
Il pacchetto NuGet Microsoft.AspNetCore.ResponseCompression contiene un middleware di compressione che possiamo aggiungere alle nostre applicazioni ASP.NET Core 1.0 e 1.1.
Da Visual Studio 2017, apriamo la Console Package Manager e digitiamo il seguente comando:
Install-Package Microsoft.AspNetCore.ResponseCompression
Mentre, se stiamo usando Visual Studio Code, dalla scheda Terminal (o direttamente dal prompt dei comandi) digitiamo:
dotnet add package Microsoft.AspNetCore.ResponseCompression dotnet restore
Ora che il pacchetto NuGet è installato, apriamo il file Startup.cs e configuriamo il middleware.
Nel metodo ConfigureServices, aggiungiamo una chiamata a AddResponseCompression:
public void ConfigureServices(IServiceCollection services) { services.AddResponseCompression(); // Qui configurazione di altri servizi }
Poi modifichiamo così il metodo Configure, avendo cura di inserire la chiamata a UseResponseCompression subito prima degli eventuali metodi UseMvc e UseStaticFiles.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseResponseCompression(); app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
Da questo momento, se avviamo l'applicazione e consultiamo gli strumenti di sviluppo del browser (tasto F12) noteremo che alcuni dei contenuti sono arrivati compressi con l'algoritmo gzip.
L'uso della compressione gzip è completamente trasparente dal punto di vista dell'applicazione client e non comporta alcuna ulteriore complessità nella comunicazione con il server.
Configurare il tipo di contenuti soggetti a compressione
I contenuti che ottengono i migliori benefici dalla compressione sono quelli testuali e, in generale, tutti quelli che contengono sequenze ripetute di byte. Ottimi candidati per la compressione sono le pagine HTML, gli stili CSS, i javascript e i dati JSON o XML, di dimensione superiore ad 1KB.
Negli altri casi, una ulteriore compressione potrebbe essere controproducente e dar luogo a trasferimenti di dimensione addirittura superiore all'originale.
Per default, i contenuti compressi dal middleware saranno:
- Testi e pagine web aventi mimetype text/plain e text/html;
- Stili e javascript con mimetype text/css, application/javascript;
- Risultati JSON o XML con mimetype application/json, text/json, text/xml, application/xml.
Se desideriamo comprimere altri tipi di contenuto, come le immagini vettoriali SVG (sono file XML), modifichiamo così la chiamata a AddResponseCompression che abbiamo aggiunto in precedenza.
services.AddResponseCompression(options => { options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "image/svg+xml" }); });
Se invece vogliamo ridefinire l'intero elenco, scriviamo:
services.AddResponseCompression(options => { options.MimeTypes = new string[] { "text/html", "text/css", "image/svg+xml" }; });
Verifichiamo che la nostra impostazione ha avuto effetto grazie agli strumenti di sviluppo del browser.
Impostare il livello di compressione
Il middleware ci permette di decidere fra 3 livelli di compressione, così come indicato dall'enumerazione CompressionLevel:
- NoCompression è il più rapido dei 3 ma non offre alcuna compressione effettiva. I dati compressi avranno una dimensione di poco superiore all'originale per via di un piccolo overhead dovuto al formato gzip;
- Fastest (è il default) offre una buona compressione senza richiedere troppa capacità elaborativa;
- Optimal richiede maggiore capacità elaborativa per comprimere i dati il più possibile.
Per impostare uno dei livelli di compressione, aggiungiamo questo blocco di codice al metodo ConfigureServices del file Startup.cs.
//Non necessario per usare Fastest, che è il default services.Configure<GzipCompressionProviderOptions>(options => { options.Level = CompressionLevel.Optimal; });
Secondo un rapido benchmark che coinvolge una risposta JSON di circa 600KB, l'opzione Fastest è il miglior compromesso tra compressione e capacità elaborativa richiesta.
Richiedere la compressione dal client
Il middleware eseguirà la compressione solo se nella richiesta HTTP è stata inclusa l'intestazione Accept-Encoding: gzip, oppure Accept-Encoding: *.
Se il nostro client è una pagina web, tale intestazione verrà automaticamente aggiunta dal browser web ogni volta che effettuiamo una richiesta ajax o carichiamo una nuova pagina web.
Lo stesso vale per un client .NET come un'applicazione Xamarin o WPF: se usiamo la classe HttpClient per inviare richieste web, l'intestazione Accept-Encoding verrà automaticamente aggiunta alle richieste. Possiamo anche configurare HttpClient in maniera esplicita per richiedere la compressione gzip in questo modo:
var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.Gzip }; using (var client = new HttpClient(handler)) { //Qui inviamo una richiesta web }
E' bene notare che il middleware di compressione supporta solo l'algoritmo gzip.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Eseguire i worklow di GitHub su runner potenziati
Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
Usare lo spread operator con i collection initializer in C#
Visualizzare le change sul plan di Terraform tramite le GitHub Actions
Ottimizzazione dei block template in Angular 17
Gestire liste di tipi semplici con Entity Framework Core
Assegnare un valore di default a un parametro di una lambda in C#
Inference di dati strutturati da testo con Semantic Kernel e ASP.NET Core Web API
Usare i servizi di Azure OpenAI e ChatGPT in ASP.NET Core con Semantic Kernel
Ottimizzare il mapping di liste di tipi semplici con Entity Framework Core
Proteggere le risorse Azure con private link e private endpoints
Code scanning e advanced security con Azure DevOps