Il processo di containerizzazione di un'applicazione .NET è essenziale per modernizzare e rendere scalabili le applicazioni web. Utilizzando Docker e Kubernetes, è possibile distribuire facilmente un'applicazione ASP.NET Core 9.0 in ambienti di produzione, riducendo la complessità e migliorando la portabilità tra diversi ambienti. In questa sezione, esploreremo i passaggi fondamentali per containerizzare e distribuire un'applicazione ASP.NET Core 9.0 utilizzando Docker e Kubernetes.

Il primo passo per preparare l'ambiente è la creazione di un'immagine Docker per l'applicazione ASP.NET Core. A partire da un'immagine base di .NET SDK, si configura il contesto di lavoro e si copia il progetto dell'applicazione all'interno del container. L'immagine di base che scegliamo è mcr.microsoft.com/dotnet/sdk:9.0, la quale include tutto il necessario per compilare e pubblicare un'applicazione .NET. A questo punto, si effettua il ripristino delle dipendenze e si compila il progetto.

Successivamente, l'applicazione viene pubblicata in una cartella separata (/app/publish) per separare la fase di build da quella di runtime, in modo da mantenere il container finale il più leggero possibile. Una volta che l'applicazione è stata pubblicata, il passaggio successivo consiste nel creare un'immagine di runtime utilizzando l'immagine base di .NET e copiando i file pubblicati dall'immagine di build.

Una volta creata l'immagine del container, si può costruire e testare localmente. Utilizzando i comandi Docker, si esegue la build dell'immagine con il comando docker build, seguita dall'esecuzione dell'immagine con docker run, che avvia il container e espone le porte necessarie per l'interazione con il servizio. Il comando docker run --rm -p 8080:8080 dotnetdocker permette di eseguire l'applicazione localmente, accessibile tramite il browser al percorso http://localhost:8080/weatherforecast.

Il passo successivo è pubblicare l'immagine in un registro di container, come Docker Hub. Per farlo, si esegue il tagging dell'immagine con il proprio nome utente su Docker Hub e la versione dell'applicazione, utilizzando il comando docker tag dotnetdocker yourdockerhubusername/dotnetdocker:tag. Dopo aver effettuato l'accesso a Docker Hub con docker login, l'immagine può essere spinta nel registro con il comando docker push yourdockerhubusername/dotnetdocker:tag.

La fase finale di distribuzione prevede l'uso di Kubernetes o di una piattaforma simile per la gestione dei container. Kubernetes facilita la gestione della distribuzione, la scalabilità e la disponibilità delle applicazioni, automatizzando la distribuzione e il bilanciamento del carico tra i container. Si creano due file di configurazione: deployment.yaml per la distribuzione del servizio e service.yaml per l'esposizione del servizio tramite un Load Balancer.

Nel file deployment.yaml, si definisce la configurazione del servizio, indicando il numero di repliche e l'immagine Docker da utilizzare. All'interno del file service.yaml, si espongono le porte per il traffico esterno e si associa l'applicazione a un Load Balancer. Dopo aver creato questi file, si applicano le configurazioni a Kubernetes con il comando kubectl apply -f deployment.yaml e kubectl apply -f service.yaml. È importante monitorare lo stato della distribuzione per garantire che l'applicazione sia in esecuzione correttamente.

Una volta distribuito, l'accesso all'applicazione avviene tramite il Load Balancer o il Node Port fornito dalla piattaforma di containerizzazione. Questo approccio migliora la scalabilità dell'applicazione e consente di gestire le risorse in modo più efficiente.

Infine, è importante ricordare alcuni principi best practice per la gestione delle applicazioni containerizzate. È fondamentale testare l'applicazione localmente prima di procedere con la distribuzione in produzione, garantendo che tutte le funzionalità siano operative. Inoltre, è consigliabile gestire i dati sensibili come le credenziali e le configurazioni tramite variabili d'ambiente o strumenti di gestione delle configurazioni offerti dalla piattaforma di containerizzazione. Mantenere le immagini Docker aggiornate e scannerizzarle per vulnerabilità è un'altra pratica essenziale per garantire la sicurezza. Monitorare costantemente le performance e la salute dell'applicazione è altrettanto importante per prevenire guasti o degrado delle performance in produzione.

In sintesi, il processo di containerizzazione e distribuzione di un'applicazione ASP.NET Core 9.0 consente di ottenere un'applicazione più portabile, scalabile e facilmente gestibile, sfruttando la potenza di Docker e Kubernetes. L'adozione di queste tecnologie aiuta le organizzazioni a semplificare la gestione delle applicazioni e a garantire che siano pronte per ambienti di produzione moderni e in continua evoluzione.

Come Implementare un Middleware Personalizzato e Utilizzare i Filtri in un Progetto ASP.NET Core 9.0 Minimal API

Quando si sviluppano applicazioni web con ASP.NET Core, è fondamentale comprendere come implementare middleware personalizzati e sfruttare i filtri per gestire il flusso delle richieste HTTP e la formattazione delle risposte. In questo contesto, il concetto di middleware rappresenta uno strumento potente che permette di inserire logiche trasversali come la gestione delle autorizzazioni, la memorizzazione nella cache e la formattazione delle risposte. Sebbene i filtri siano un concetto più comune nelle applicazioni basate su controller MVC, in un'API minima (Minimal API) di ASP.NET Core, i filtri non sono supportati direttamente. Tuttavia, esistono approcci alternativi, tra cui l'uso dei middleware, per ottenere un comportamento simile.

Per comprendere pienamente come costruire e testare un middleware personalizzato in un progetto Minimal API, consideriamo i seguenti passaggi pratici.

Creazione di un Nuovo Progetto ASP.NET Core Minimal API

Per iniziare, bisogna creare un nuovo progetto ASP.NET Core Minimal API. Questo può essere fatto tramite la riga di comando, eseguendo i seguenti comandi:

bash
mkdir middlewareapi cd middlewareapi dotnet new webapi

Successivamente, apriamo il progetto nel nostro editor di codice preferito, come Visual Studio Code:

bash
code .

A questo punto, abbiamo creato la base del nostro progetto API e possiamo iniziare a configurare il middleware.

Implementazione di un Middleware Personalizzato

In ASP.NET Core, il middleware è una serie di componenti che elaborano le richieste HTTP e le risposte. Un middleware personalizzato può essere aggiunto facilmente modificando il file Program.cs. Supponiamo di voler implementare un middleware di logging che registra quando una richiesta arriva e quando una risposta viene inviata. Ecco come potrebbe essere configurato:

Nel file Program.cs, aggiungiamo il middleware personalizzato di logging:

csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build(); // Middleware personalizzato per il logging app.Use(async (context, next) => { Console.WriteLine("Richiesta in arrivo"); await next(); Console.WriteLine("Risposta in uscita"); }); // Definizione delle rotte app.MapGet("/", () => "Ciao mondo"); app.Run();

In alternativa, possiamo creare una classe di middleware separata. Creiamo un nuovo file chiamato LoggingMiddleware.cs:

csharp
using Microsoft.AspNetCore.Http; using System.Threading.Tasks; public class LoggingMiddleware { private readonly RequestDelegate _next; public LoggingMiddleware(RequestDelegate next) { _next = next; }
public async Task InvokeAsync(HttpContext context)
{ Console.WriteLine(
"LoggingMiddleware>> Richiesta in arrivo"); await _next(context); Console.WriteLine("LoggingMiddleware>> Risposta in uscita"); } }

Poi, nel file Program.cs, possiamo utilizzare il middleware personalizzato aggiungendo la seguente linea di codice:

csharp
app.UseMiddleware<LoggingMiddleware>();

Implementazione di un Filtro Semplice (Opzionale in Minimal API)

In un progetto Minimal API, i filtri non sono direttamente supportati come nel tradizionale modello basato su controller MVC. Tuttavia, è possibile ottenere una funzionalità simile attraverso l'uso di middleware o iniezione di servizi nei delegati degli endpoint. In questo laboratorio, ci concentreremo sul middleware per dimostrare come implementare un filtro simile.

Se desideriamo una gestione più avanzata dei filtri, potrebbe essere necessario passare a un approccio basato su controller per sfruttare i filtri MVC standard, ma il middleware rimane una soluzione potente e flessibile per la maggior parte degli scenari in un'API minima.

Costruzione e Esecuzione dell'Applicazione

Per costruire e eseguire il progetto, utilizziamo il seguente comando:

bash
dotnet run

Se desideriamo eseguire l'applicazione utilizzando il profilo HTTPS, possiamo eseguire:

bash
dotnet run --launch-profile https

Creazione del File .http per il Test del Middleware

Per testare il nostro middleware, possiamo creare un file .http con il contenuto seguente:

http
@middlewareapi_HostAddress = http://localhost:5104 GET {{middlewareapi_HostAddress}}/weatherforecast Accept: application/json

Ricordiamo che il numero di porta 5104 deve essere modificato in base alla porta effettiva mostrata nel terminale.

Test del Middleware

Per testare il middleware, apriamo il file .http in Visual Studio Code e utilizziamo l'estensione REST Client per inviare la richiesta. Osserviamo l'output della console per verificare che il middleware stia funzionando correttamente. Vedremo che le informazioni di logging appaiono nella console, segnalando l'ingresso e l'uscita delle richieste.

Un altro modo per testare il middleware è utilizzare l'interfaccia Swagger. Apriamo un browser web e navighiamo verso https://localhost:5062/swagger (assicurandoci di utilizzare la porta corretta visualizzata nel terminale).

Conclusioni

In questo laboratorio, abbiamo implementato un middleware personalizzato in un'applicazione ASP.NET Core 9.0 Minimal API. Questo middleware effettua il logging delle richieste HTTP prima e dopo che vengano elaborate. Sebbene le Minimal API non supportino i filtri come nelle applicazioni basate su controller MVC, il middleware rappresenta un'alternativa potente per la gestione delle richieste HTTP. Grazie alla sua semplicità e flessibilità, è un ottimo strumento per molti scenari di elaborazione delle richieste.

Inoltre, è fondamentale comprendere che il middleware non si limita alla registrazione dei log, ma può essere utilizzato per una varietà di compiti: dalla gestione degli errori alla validazione delle richieste, fino alla gestione della sicurezza. Un middleware ben progettato permette di applicare logiche comuni a tutte le richieste in modo trasparente, senza intaccare la logica degli endpoint specifici. La modularità e la riusabilità del middleware rappresentano un vantaggio significativo nel mantenere il codice pulito e facilmente manutenibile.