Tra le funzionalità di maggior pregio di ASP.NET WebAPI, vi è l'implementazione della cosiddetta content negotiation, che permette ad un client di indicare un formato preferito nell'ottenere dati dal server. Inviando una richiesta HTTP con l'intestazione Accept valorizzata su application/json o application/xml, il client potrà così chiedere di ottenere contenuto JSON o XML, a sua discrezione.
Se si rendesse necessario supportare altri formati, come ad esempio CSV o particolari tracciati testuali, ci basterà scrivere un MediaTypeFormatter personalizzato, ovvero quel componente della pipeline di ASP.NET WebAPI che si occupa di serializzare i nostri oggetti nel formato desiderato (o, viceversa, di deserializzare oggetti CLR da una richiesta).
Dunque aggiungiamo una nuova classe al nostro progetto (ad esempio in una cartella /Formatters) e facciamola derivare da una delle due classi astratte che troviamo nel namespace System.Net.Http.Formatting:
- MediaTypeFormatter è il tipo da cui dobbiamo derivare se vogliamo sfruttare appieno il pattern asincrono basato sui Task. Utile in casi particolari, quando la serializzazione può prolungarsi per un certo periodo di tempo a causa di frequenti letture o scritture su risorse di I/O quali rete, disco o database.
- BufferedMediaTypeFormatter è forse più immediata da utilizzare, dato che nasconde il pattern asincrono usato dal MediaTypeFormatter dietro i suoi metodi sincroni. È il tipo base che useremo in questo esempio.
Ecco dunque come si presenta il nostro MediaTypeFormatter personalizzato, che progettiamo allo scopo di serializzare elenchi di oggetti nel formato CSV.
public class CsvMediaTypeFormatter : BufferedMediaTypeFormatter { public CsvMediaTypeFormatter() { // Dal costruttore aggiungiamo i media types supportati SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv")); SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/csv")); } public override bool CanWriteType(Type type) { //Dichiariamo quali sono i tipi di oggetti che questo //MediaTypeFormatter riuscirà a formattare //Restituiamo true quando l'action ci fornisce un elenco //generico di oggetti, come IEnumerable<T> return typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType; } public override bool CanReadType(Type type) { //Un MediaTypeFormatter può anche essere impiegato //per deserializzare oggetti da una richiesta HTTP //In questo esempio restituiamo false, perché non //vogliamo supportare questo scenario return false; } public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content) { //TODO: qui scriveremo i dati in formato CSV sullo Stream della risposta } }
Ora che abbiamo visto i membri essenziali di un MediaTypeFormatter, passiamo ad implementare la logica di formattazione CSV. Per semplificare questo compito, possiamo avvalerci del pacchetto CsvHelper, scaricabile da NuGet. Dunque digitiamo il comando di installazione nella Package manager console di Visual Studio:
Install-Package CsvHelper
Finalmente abbiamo tutto ciò che ci serve per completare l'implementazione del metodo WriteToStream.
public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content) { using (var streamWriter = new StreamWriter(writeStream)) { using (var csvWriter = new CsvHelper.CsvWriter(streamWriter)) { //Scriviamo i nomi dei campi come prima riga dell'output CSV csvWriter.WriteHeader(type.GetGenericArguments().First()); //Poi forniamo l'elenco degli oggetti al metodo WriteRecords csvWriter.WriteRecords(value as IEnumerable); } } }
Non resta che aggiungere il MediaTypeFormatter alla configurazione della nostra WebAPI, così che vada ad affiancarsi ai già supportati JsonMediaTypeFormatter ed XmlMediaTypeFormatter.
Dunque apriamo il file /App_Start/WebApiConfig.cs e digitiamo:
config.Formatters.Add(new CsvMediaTypeFormatter());
A questo punto possiamo verificare il corretto funzionamento del nostro CsvMediaTypeFormatter. Rivolgiamo una richiesta HTTP ad una nostra action che restituisca un elenco di oggetti, ricordandoci di includere l'intestazione Accept: application/csv.
GET /api/catalogo HTTP/1.1 Host: localhost Accept: application/csv
Come previsto, ASP.NET WebAPI rispetta la preferenza che abbiamo espresso con l'intestazione Accept, e restituisce l'output CSV prodotto dal nostro CsvMediaTypeFormatter.
HTTP/1.1 200 OK Content-Type: application/csv Server: Microsoft-IIS/8.0 Content-Length: 228 Codice,Descrizione,PrezzoInEuro,Quantita,DisponibileDal 1000,Tavolino 4 posti,"90,00",0,31/10/2014 00:00:00 1001,"Sedia ""Ortensia"" in legno","20,00",0, 1002,Divano relax in ecopelle,"320,00",0,01/10/2014 00:00:00
E' importante apprezzare la modularità di ASP.NET WebAPI, che ci ha consentito di lasciare completamente inalterata la logica applicativa presente nei nostri ApiController. Grazie ad un MediaTypeFormatter personalizzato, infatti, siamo riusciti ad aggiungere il supporto ad un nuovo formato senza dover creare nuove action o modificare le action già esistenti.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Utilizzare le collection expression in C#
Utilizzare Tailwind CSS all'interno di React: primi componenti
Creare gruppi di client per Event Grid MQTT
Gestire domini wildcard in Azure Container Apps
Gestire i null nelle reactive form tipizzate di Angular
Usare un KeyedService di default in ASP.NET Core 8
Hosting di componenti WebAssembly in un'applicazione Blazor static
Migrare una service connection a workload identity federation in Azure DevOps
Evitare la script injection nelle GitHub Actions
Come migrare da una form non tipizzata a una form tipizzata in Angular
Sfruttare lo stream rendering per le pagine statiche di Blazor 8
Aggiungere interattività lato server in Blazor 8
I più letti di oggi
- Utilizzare Docker Compose con Azure App Service
- Utilizzare QuickGrid di Blazor con Entity Framework
- Modernizzare le applicazioni WPF e Windows Forms con Blazor
- ASP 3 per esempi
- annunciato #netstandard 2.1. .NET Core lo supporterà a partire da #netcore3, così come le prossime versione di #xamarin, #mono e #unity.il supporto per #netfx 4.8, invece, non ci sarà. https://aspit.co/bq2