Lo sviluppo di applicazioni web ha subito una trasformazione radicale nel corso degli anni, evolvendosi da un modello client-server semplice, basato su poche tecnologie, a ecosistemi complessi e ricchi di funzionalità. Originariamente, per realizzare un'applicazione web bastavano pochi file JavaScript, un linguaggio interpretato lato server come PHP o Perl, e un database per la persistenza dei dati. Tuttavia, la crescente domanda di esperienze utente più interattive e dinamiche ha spinto lo sviluppo verso nuovi orizzonti, in cui le tecnologie si intrecciano e si sovrappongono.

Il modello tradizionale non è più sufficiente: la nascita di framework JavaScript avanzati e l'affermazione delle Single-Page Applications (SPA) hanno rivoluzionato il modo di concepire le web app, spostando parte della logica e del rendering dal server al client, migliorando sensibilmente la reattività e la ricchezza dell'interazione. Allo stesso tempo, il backend continua a evolversi, integrando processi più sofisticati e potenti capaci di supportare questi nuovi paradigmi.

In questo contesto, la complessità tecnologica cresce in modo esponenziale: non si parla più di poche tecnologie isolate, ma di un vero e proprio ecosistema composto da linguaggi, framework, pacchetti, design pattern, standard e architetture diversificate. A questa complessità si aggiunge la necessità di integrazione con ambienti cloud, che richiede competenze aggiuntive e un cambio di mentalità verso una progettazione cloud-native.

Le sfide non si limitano alle tecnologie stesse, ma si estendono anche all’organizzazione del lavoro: i team di sviluppo devono padroneggiare più linguaggi e strumenti, combinandoli in modo sostenibile e collaborativo. Ciò implica una continua formazione, aggiornamento e l'adozione di best practice che permettano di mantenere alta la qualità del software e di adattarsi rapidamente alle mutevoli esigenze di mercato.

In questo scenario si inserisce la piattaforma ASP.NET Core 9, una soluzione open source moderna di Microsoft che sintetizza in un’unica piattaforma un insieme di strumenti e metodologie pensati per costruire applicazioni di alta qualità, modulari, estendibili e adatte a diversi ambienti di esecuzione, dal locale al cloud. ASP.NET Core 9 supporta appieno i principi del cloud-native, integrando funzionalità per sicurezza, resilienza, monitoraggio e gestione della configurazione, elementi fondamentali per le applicazioni di nuova generazione.

Comprendere questa evoluzione è cruciale per chi si occupa di sviluppo software: non basta conoscere un linguaggio o un framework, ma è necessario adottare un approccio olistico che consideri l’intero ciclo di vita dell’applicazione, dalla progettazione alla distribuzione e manutenzione, con un’attenzione particolare alla sicurezza, alla scalabilità e all’esperienza utente. Solo così si può garantire la realizzazione di soluzioni capaci di rispondere efficacemente ai bisogni di un mercato in costante mutamento, mantenendo un vantaggio competitivo.

È importante inoltre riconoscere che la tecnologia non è un fine a sé stessa, ma un mezzo al servizio di obiettivi di business e di esigenze concrete. La scelta di strumenti e architetture deve essere guidata da una chiara visione delle funzionalità richieste e dei vincoli di progetto, tenendo presente l’impatto sul team di sviluppo e sulla capacità di mantenere il software nel tempo. La combinazione di competenze tecniche approfondite, metodologie agili e un forte orientamento alla qualità rappresenta la chiave per affrontare con successo le sfide dello sviluppo web moderno.

Come migliorare le prestazioni delle applicazioni con il middleware in ASP.NET Core 9

Il codice che vediamo in questo esempio ha lo scopo di misurare il tempo di esecuzione di una richiesta. Si tratta di un approccio interessante per misurare i limiti della tua applicazione, permettendo di migliorare le prestazioni dell'implementazione. Aggiungere funzionalità alle applicazioni utilizzando il middleware è una delle tecniche principali per ottimizzare il comportamento e la gestione delle risorse.

Nel contesto di questo esempio, possiamo analizzare i seguenti aspetti:

  • Iniezione delle dipendenze (DI): Il metodo InvokeAsync accetta un parametro ILogger, che viene fornito tramite iniezione delle dipendenze (DI).

  • Registrazione delle metriche delle richieste: Il metodo InvokeAsync utilizza l'istanza ILogger per registrare il metodo HTTP, il percorso della richiesta e il tempo impiegato per elaborarla.

  • Raccolta del tempo di esecuzione della richiesta: Prima di eseguire la richiesta, si utilizza il metodo statico GetTimestamp() della classe Stopwatch per ottenere il timestamp iniziale. Dopo aver eseguito la richiesta tramite la delega _await _next(context), il metodo Stop della classe Stopwatch viene utilizzato per fermare il timer. Un log viene quindi creato contenente informazioni sulla richiesta, come il metodo, il percorso e il tempo di esecuzione in millisecondi, ottenuti tramite il metodo GetElapsedTime(timestamp).TotalMilliseconds.

La classe Stopwatch in .NET è un timer ad alta risoluzione fornito dal namespace System.Diagnostics. Viene utilizzata per misurare il tempo trascorso con grande precisione, rendendola ideale per compiti di misurazione delle prestazioni e benchmarking. Questa funzionalità è particolarmente utile quando si desidera ottenere informazioni accurate sull'efficienza dell'applicazione.

Quando implementiamo log personalizzati come PerformanceLoggingMiddleware, creare un middleware personalizzato migliora le funzionalità delle nostre applicazioni, supportando sia l’esperienza degli utenti che la manutenzione e diagnosi da parte dei team. Inoltre, facilita l'evoluzione dell'applicazione nel tempo.

ASP.NET Core 9 offre anche altri middleware capaci di affrontare diversi aspetti importanti del flusso di esecuzione di un'applicazione. Uno di questi è il middleware di rate limiting, che esploreremo nel dettaglio.

Il middleware di rate limiting

Il middleware di rate limiting in ASP.NET Core 9 è una funzionalità potente e fondamentale per proteggere le applicazioni da abusi e migliorare le prestazioni e l'affidabilità complessive. Questo middleware controlla il numero di richieste che un client può fare a un server entro un periodo di tempo specificato.

Per utilizzare il middleware di rate limiting in ASP.NET Core 9, è necessario configurarlo nel file Program.cs dell'applicazione. Ecco un esempio di implementazione:

csharp
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.RateLimiting; using System.Threading.RateLimiting; var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); // Configura le politiche di rate limiting builder.Services.AddRateLimiter(options => { options.AddPolicy("fixed", context => RateLimitPartition.GetFixedWindowLimiter(new RateLimitPartitionKey(context.Request.Headers["X-Forwarded-For"].ToString(), PartitionKeyKind.ClientIP), partition => new FixedWindowRateLimiterOptions { PermitLimit = 5, Window = TimeSpan.FromMinutes(1), QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 2 })); options.AddPolicy("sliding", context => RateLimitPartition.GetSlidingWindowLimiter(new RateLimitPartitionKey(context.Request.Headers["X-Forwarded-For"].ToString(), PartitionKeyKind.ClientIP), partition => new SlidingWindowRateLimiterOptions { PermitLimit = 5, Window = TimeSpan.FromMinutes(1), SegmentsPerWindow = 3, QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 2 })); options.AddPolicy("tokenBucket", context => RateLimitPartition.GetTokenBucketLimiter(new RateLimitPartitionKey(context.Request.Headers["X-Forwarded-For"].ToString(), PartitionKeyKind.ClientIP), partition => new TokenBucketRateLimiterOptions { TokenLimit = 10, TokensPerPeriod = 5, ReplenishmentPeriod = TimeSpan.FromSeconds(10), QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 2 })); }); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // Usa il middleware di rate limiting app.UseRateLimiter(); app.MapRazorPages(); app.Run();

In questo esempio, abbiamo configurato tre politiche di rate limiting:

  1. Finestra fissa: Limita le richieste a 5 per minuto. Una volta raggiunto il limite, nessuna richiesta sarà accettata fino al reset della finestra.

  2. Finestra mobile: Simile alla finestra fissa, ma suddivide la finestra in segmenti, permettendo una distribuzione più equilibrata delle richieste per minuto.

  3. Secchiello di token: Consente di avere fino a 10 token (richieste), con 5 nuovi token riforniti ogni 10 secondi. Se i token finiscono, le richieste in arrivo vengono messe in coda.

Il middleware di rate limiting in ASP.NET Core 9 offre numerosi vantaggi, tra cui:

  • Protezione contro il sovraccarico: Previene il sovraccarico del server a causa di troppe richieste, garantendo prestazioni stabili.

  • Uso equo delle risorse: Assicura che nessun client monopolizzi le risorse del server, promuovendo un accesso equo per tutti gli utenti.

  • Sicurezza: Mitiga alcuni tipi di attacchi, come gli attacchi DDoS, limitando il numero di richieste che i client possono inviare.

  • Miglioramento dell'esperienza dell'utente: Impedendo il sovraccarico del server, il rate limiting contribuisce a mantenere tempi di risposta consistenti e la disponibilità del servizio.

Conoscere le politiche di rate limiting è cruciale per lo sviluppo di applicazioni sicure e ad alte prestazioni. L'integrazione di questo tipo di middleware permette di gestire il traffico in modo più efficiente, soprattutto in ambienti in cui le risorse sono limitate o quando ci si aspetta un traffico elevato.

Oltre al rate limiting, ASP.NET Core 9 offre una varietà di middleware per soddisfare diverse esigenze, come l'autenticazione e l'autorizzazione, che sono essenziali per la protezione delle applicazioni moderne. È importante essere consapevoli delle implicazioni di ogni middleware che si utilizza, in quanto la loro combinazione può influire significativamente sull’efficienza, la sicurezza e la scalabilità dell'applicazione.

Come configurare e pubblicare un’applicazione ASP.NET Core su Azure: connessioni, sicurezza e deployment automatizzato

Per iniziare, è fondamentale accedere al gruppo di risorse precedentemente creato, ad esempio rg-aspnetcore8, dove si visualizzerà l’elenco delle risorse allocate. Da qui, bisogna individuare la risorsa UrlshortenerDB e aprirla per gestire la connessione al database. Nelle impostazioni, sotto la voce Connection Strings, si trova la stringa di connessione necessaria per collegare l’applicazione al database SQL ospitato su Azure. Questa stringa contiene parametri come il server, il catalogo iniziale, l’ID utente e la password. È essenziale sostituire il segnaposto della password con quella reale, ottenuta in fase di creazione dei servizi applicativi.

La stringa di connessione copiata dall’interfaccia di Azure deve essere inserita nel file di configurazione appsettings.json dell’applicazione URLShortener, sostituendo il valore di DefaultConnection. Questo file controlla come l’applicazione interagisce con il database e il corretto inserimento della stringa permette di stabilire la comunicazione necessaria per il funzionamento dell’app.

Successivamente, la configurazione della sicurezza è altrettanto cruciale. Tornando nel gruppo di risorse e selezionando il server del database, si deve aggiungere l’indirizzo IPv4 del client tramite la sezione Networking e la funzione “Add your client IPv4 address”. Questo passaggio configura una regola firewall che consente l’accesso al database esclusivamente dall’indirizzo IP specificato, limitando così potenziali rischi di accessi non autorizzati. Tuttavia, questa configurazione implica che ogni modifica dell’IP richiederà una nuova aggiunta alla whitelist.

Dopo aver salvato queste impostazioni, si procede con l’aggiornamento del database. Attraverso il terminale, nella cartella del progetto URLShortener, si esegue il comando dotnet ef database update, che applica le migrazioni definite con Entity Framework Core, aggiornando lo schema del database in base al modello di dati dell’applicazione. Questa operazione è fondamentale per mantenere sincronizzati database e codice applicativo, evitando incongruenze che possono causare errori di runtime.

Per pubblicare l’applicazione su Azure, Visual Studio Code con l’estensione Azure Tools facilita notevolmente il processo. Una volta aperta la directory del progetto con il comando code ., si seleziona l’icona dell’estensione Azure Tools per visualizzare le sottoscrizioni e le risorse disponibili. Il deployment si avvia cliccando con il tasto destro sull’App Service dell’applicazione e selezionando “Deploy to Web App…”. Confermate le configurazioni proposte, il processo di pubblicazione inizia e viene eseguito automaticamente in background. L’estensione si occupa di restaurare i pacchetti necessari, compilare il progetto, creare il pacchetto di pubblicazione, comprimerlo in formato ZIP, caricarlo sul servizio Azure e scompattarlo, rendendo l’applicazione immediatamente disponibile online.

Questa procedura semplifica notevolmente il rilascio continuo di nuove versioni, rendendo l’aggiornamento del servizio fluido e poco soggetto a errori manuali. Inoltre, la configurazione descritta rappresenta una modalità base di deployment che può evolversi verso approcci più complessi come il CI/CD, integrati in flussi DevOps moderni, che automatizzano ulteriormente build, test e rilascio.

Infine, è importante comprendere che la scelta dell’ambiente di hosting e della strategia di deployment deve essere guidata non solo dai requisiti tecnici dell’applicazione, ma anche dal contesto organizzativo e dalle competenze del team di sviluppo. La containerizzazione, ad esempio, rappresenta un paradigma sempre più diffuso che consente di isolare l’applicazione in ambienti standardizzati, eliminando problematiche dovute a dipendenze ambientali differenti. L’adozione di container rende inoltre più semplice il passaggio tra ambienti diversi (sviluppo, test, produzione) e favorisce scalabilità e portabilità.

È altresì fondamentale considerare le implicazioni di sicurezza nella gestione delle credenziali, nel controllo degli accessi IP e nell’aggiornamento continuo delle dipendenze, per garantire un’operatività stabile e protetta in ambienti cloud complessi come Azure.

Come si crea e si configura una prima applicazione web con ASP.NET Core 9 e il modello MVC?

Per iniziare a sviluppare un’applicazione web utilizzando ASP.NET Core 9, uno dei primi passi fondamentali è la creazione del progetto tramite il template MVC, che segue il modello architetturale Model-View-Controller. Questo modello consente una chiara separazione tra la gestione dei dati (Model), la visualizzazione dell’interfaccia (View) e la logica di controllo (Controller). Per ora non è necessario approfondire ogni dettaglio tecnico, poiché nel corso della lettura si acquisiranno le competenze necessarie a comprendere appieno questi concetti.

La creazione del progetto avviene con un semplice comando nel terminale:
dotnet new mvc --name my-first-app
Questo comando genera la struttura base di un’applicazione MVC, con tutte le cartelle e i file necessari per iniziare. Successivamente si entra nella directory del progetto tramite cd my-first-app e si apre l’editor Visual Studio Code con code . per poter intervenire sul codice sorgente.

Una modifica tipica consiste nel personalizzare la pagina iniziale, ad esempio aggiornando il file index.cshtml nella cartella Views/Home. Modificando la linea contenente il testo di benvenuto, si può visualizzare un messaggio più attuale, come “Welcome to the ASP.NET Core 9!”. Salvando il file e ritornando al terminale, con il comando dotnet run si avvia l’applicazione, che sarà accessibile via browser all’indirizzo indicato nella console, generalmente http://localhost seguito da una porta specifica.

Se tutto funziona correttamente, si avrà conferma che l’ambiente di sviluppo, il codice e l’SDK .NET sono configurati in modo adeguato. Qualora sorgano problemi, è necessario rivedere le fasi di installazione e configurazione relative al proprio sistema operativo.

ASP.NET Core 9 si presenta come una piattaforma open source, multipiattaforma, che negli ultimi anni ha subito numerosi miglioramenti. Tra questi, la possibilità di compilare applicazioni in modalità Native AOT, riducendo significativamente le dimensioni del file eseguibile e migliorando la performance su architetture x64 e ARM64, soprattutto in ambienti Linux e macOS. Inoltre, sono stati ottimizzati i sistemi di serializzazione dei dati JSON tramite la libreria System.Text.Json, ormai sempre più indipendente da soluzioni esterne e in grado di fornire una gestione più efficiente e performante.

La crescita della piattaforma è il risultato di un’intensa collaborazione tra la comunità di sviluppatori, Microsoft e la .NET Foundation. Questa sinergia garantisce aggiornamenti continui, correzioni di bug e l’implementazione di nuove funzionalità rispondendo alle esigenze di mercato e alle richieste degli utenti. Inoltre, ASP.NET Core si adatta perfettamente allo sviluppo di soluzioni web moderne, offrendo diversi approcci per la realizzazione dell’interfaccia utente, sia sul lato server che sul lato client.

In particolare, la UI in ASP.NET Core 9 può essere realizzata tramite Razor Pages, il modello MVC classico, oppure con framework client-side come Blazor, che permette di scrivere logica client in C#. L’interazione tra frontend e backend è alla base delle applicazioni web dinamiche: il frontend, eseguito nel browser, si occupa della visualizzazione e dell’interazione utente, mentre il backend gestisce i dati e la logica di business sul server, rispondendo alle richieste dell’interfaccia.

Il browser utilizza principalmente tre tecnologie: HTML per la struttura della pagina, CSS per la definizione degli stili visivi e JavaScript per rendere dinamici gli elementi, ad esempio aggiornando l’interfaccia senza dover ricaricare la pagina completamente. Questo paradigma client-server costituisce la base del funzionamento delle moderne applicazioni web.

La comprensione del corretto flusso tra frontend e backend è cruciale per sviluppare applicazioni efficienti e responsive. È importante inoltre conoscere le differenze tra le varie modalità di rendering offerte da ASP.NET Core, come il rendering server-side con Razor Pages e MVC, o il rendering client-side con Blazor o altre librerie JavaScript, così da scegliere la soluzione più adatta a ogni scenario specifico.

La configurazione iniziale dell’ambiente, la conoscenza dei modelli architetturali e le nozioni sulle tecnologie di frontend e backend sono elementi imprescindibili per chi vuole padroneggiare lo sviluppo di applicazioni web con ASP.NET Core 9. È essenziale anche tenere conto della continua evoluzione della piattaforma e delle pratiche consigliate dalla comunità, per sfruttarne appieno le potenzialità e garantire applicazioni robuste e performanti.

Come Progettare Soluzioni Cloud-Native: Principi e Strumenti Fondamentali

Nel panorama in continua evoluzione dell'informatica e delle tecnologie basate sul cloud, la progettazione di soluzioni cloud-native rappresenta una sfida cruciale per le aziende che vogliono massimizzare l’efficienza, la sicurezza e la scalabilità delle loro applicazioni. Sebbene la transizione verso il cloud offra numerosi vantaggi, è essenziale che le organizzazioni seguano un approccio strategico e ben strutturato per evitare le insidie di un'adozione disorganizzata. In questo contesto, due risorse fondamentali emergono: il Cloud Adoption Framework (CAF) e il Well-Architected Framework (WAF). Entrambi offrono linee guida cruciali per la progettazione, la gestione e l'ottimizzazione delle soluzioni cloud-native.

Il CAF, sviluppato da Microsoft, è una fonte di conoscenza eccellente per la pianificazione e la governance dell’adozione del cloud. Sebbene il CAF si concentri sull'intera struttura dell’ambiente cloud, piuttosto che su singole applicazioni o carichi di lavoro specifici, può essere un valido punto di riferimento anche nella progettazione di nuove soluzioni. Includendo i team aziendali, di sviluppo e di infrastruttura, il framework favorisce la creazione di un flusso continuo di consegna, favorendo un'adozione che si allinea strettamente con gli obiettivi aziendali.

Parallelamente, il WAF si presenta come un insieme di capacità indispensabili per la progettazione e la gestione di infrastrutture sicure, performanti e resilienti. Il WAF è suddiviso in cinque pilastri chiave, ognuno dei quali contribuisce in modo significativo alla creazione di soluzioni cloud-native ottimizzate:

  1. Eccellenza operativa: si concentra sui processi che garantiscono il corretto funzionamento delle applicazioni, inclusi monitoraggio, automazione e risposta agli incidenti.

  2. Sicurezza: tutela le applicazioni e i dati dalle minacce, coprendo gestione delle identità, protezione delle infrastrutture, crittografia e rilevamento delle minacce.

  3. Affidabilità: assicura che le applicazioni possano riprendersi rapidamente da eventuali guasti e continuare a funzionare come previsto, comprendendo strategie di disaster recovery, tolleranza ai guasti e backup dei dati.

  4. Efficienza delle performance: garantisce che le applicazioni utilizzino le risorse in modo ottimale, affrontando pianificazione della capacità, ottimizzazione delle risorse e monitoraggio delle performance.

  5. Ottimizzazione dei costi: mira alla gestione efficace dei costi, mantenendo un equilibrio tra performance e valore, attraverso il monitoraggio dei costi, l'analisi dell'utilizzo e l'implementazione di strategie di riduzione dei costi.

Oltre a fornire una documentazione dettagliata, il WAF mette a disposizione anche strumenti pratici come assessment, checklist e altre risorse che facilitano l'analisi e il miglioramento dei carichi di lavoro esistenti nel cloud.

Un altro concetto fondamentale per la progettazione di soluzioni cloud-native è il passaggio da una mentalità di sviluppo software tradizionale a una che tenga conto anche dell'infrastruttura, della sicurezza, dei dati e della rete. Le soluzioni cloud-native non possono limitarsi alla creazione di semplici applicazioni; devono essere progettate per sfruttare appieno le potenzialità offerte dall’ambiente cloud, adattandosi continuamente alle esigenze di mercato. La cultura DevOps, con la sua enfasi sulla collaborazione tra team di sviluppo e operazioni, è essenziale per raggiungere questo obiettivo. DevOps non riguarda solo la comunicazione efficace tra i team, ma anche la condivisione di conoscenze, standard e buone pratiche.

Un aspetto cruciale è comprendere la differenza tra agilità e velocità nello sviluppo di applicazioni cloud-native. L’agilità implica una capacità di adattarsi rapidamente a nuovi requisiti o cambiamenti, mentre la velocità si riferisce alla rapidità con cui una soluzione viene sviluppata e rilasciata. In un mondo altamente competitivo, essere agili non significa semplicemente essere veloci; è necessario bilanciare entrambi gli aspetti per ottimizzare i processi di sviluppo senza sacrificare la qualità.

Un altro principio fondamentale nella progettazione di soluzioni cloud-native è l'utilizzo di strumenti adeguati. L’approccio cloud-native si distingue per l’uso di tecnologie come i container, gli orchestratori e i microservizi, che permettono di costruire applicazioni modulari, scalabili e facilmente gestibili. Tali strumenti consentono di creare architetture di sistemi più flessibili e robuste, in grado di rispondere in modo efficace alle sfide di un ambiente cloud in continua evoluzione.

Infine, un altro concetto che sta prendendo sempre più piede è il modello cloud-agnostico, che promuove l'indipendenza da un singolo fornitore di servizi cloud, come Azure, AWS o GCP. Questo approccio consente alle organizzazioni di progettare soluzioni che possano essere facilmente portate su diverse piattaforme, senza dipendere dalle specificità di un singolo provider. La Cloud Native Computing Foundation (CNCF) gioca un ruolo fondamentale in questo contesto, favorendo l'adozione di tecnologie aperte e standard che consentono alle applicazioni cloud-native di operare in modo interoperabile e sostenibile.

Le aziende che adottano questo paradigma devono essere pronte a evolversi continuamente, con un’attenzione costante alla qualità del codice, alla gestione dell’infrastruttura e alla sicurezza. In questo senso, la conoscenza delle risorse disponibili, come i framework CAF e WAF, nonché degli strumenti di containerizzazione e microservizi, è fondamentale per costruire soluzioni che siano non solo funzionali ma anche ottimizzate per l’ambiente cloud.