ASP.NET Web API si rivela un'ottima tecnologia per esporre un servizio ai nostri utenti remoti. Tuttavia, le latenze di rete e l'inevitabile overhead del protocollo HTTP potrebbero limitare la loro capacità di inviare numeri elevati di richieste nell'unità di tempo.
Il supporto al batching di ASP.NET Web API 2 è un efficace rimedio a questo problema, perché consente l'invio di molteplici richieste HTTP con un singolo round-trip al server.
Il guadagno prestazionale non è facilmente stimabile a causa di vari fattori ma, in linea generale, a trarne maggior beneficio saranno quei client che inviano al servizio molte piccole richieste in rapida sequenza.
Di per sé, il batching non implica che le richieste verranno eseguite nell'ambito di una transazione. Piuttosto, il suo scopo è quello di farci raggiungere un throughput più elevato, opzionalmente mantenendo un'esecuzione sequenziale delle richieste.
Lato server, andiamo a configurare un'apposita route da destinare a questo scopo. Aggiungiamo le seguenti linee di codice al corpo del metodo Register, che si trova nel file App_Start/WebApiConfig.cs di un tipico progetto ASP.NET Web API.
config.Routes.MapHttpBatchRoute( routeName: "batch", routeTemplate: "api/batch", batchHandler: new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer){ ExecutionOrder = BatchExecutionOrder.Sequential //indichiamo NonSequential se l'ordine sequenziale non ci interessa } );
Il DefaultHttpBatchHandler si occuperà di estrarre dal batch tutte le richieste HTTP e di reintrodurle, una ad una, nella pipeline di elaborazione del servizio, proprio come se fossero arrivate singolarmente. Successivamente, aggiungerà i loro risultati al contenuto di un'unica risposta.
Lato client, prepariamo la richiesta batch usando le classi del namespace System.Net.Http.
//Definiamo l'URL base del servizio ASP.NET Web API. string baseAddress = "http://localhost:56813/"; //Iniziamo col preparare le singole richieste HTTP da includere nel batch //In questo esempio, le prime due sono richieste POST per inviare dei dati... HttpRequestMessage inserisciTemperaturaRoma = new HttpRequestMessage( HttpMethod.Post, baseAddress + "api/temperature/roma") { Content = new ObjectContent<string>("15.5 °C", new JsonMediaTypeFormatter()) }; HttpRequestMessage inserisciTemperaturaMilano = new HttpRequestMessage( HttpMethod.Post, baseAddress + "api/temperature/milano") { Content = new ObjectContent<string>("12.7 °C", new JsonMediaTypeFormatter()) }; //...e la terza è una richiesta GET per ottenere un valore HttpRequestMessage leggiMediaItaliana = new HttpRequestMessage( HttpMethod.Get, baseAddress + "api/temperature/italia/media"); //Creiamo la richiesta batch vera e propria, assegnandole un contenuto //multipart/mixed. Il MultipartContent ci consente di aggiungere le 3 //richieste che abbiamo appena preparato HttpRequestMessage richiestaBatch = new HttpRequestMessage( HttpMethod.Post, baseAddress + "api/batch") { Content = new MultipartContent("mixed"){ new HttpMessageContent(inserisciTemperaturaRoma), new HttpMessageContent(inserisciTemperaturaMilano), new HttpMessageContent(leggiMediaItaliana) } }; //Finalmente inviamo la richiesta batch usando un'istanza di HttpClient HttpClient client = new HttpClient(); HttpResponseMessage rispostaBatch = client.SendAsync(richiestaBatch).Result; //Assicuriamoci che la richiesta batch abbia avuto successo rispostaBatch.EnsureSuccessStatusCode(); //Anche la risposta sarà di tipo multipart/mixed, ovvero conterrà //un insieme di contenuti IEnumerable<HttpContent> contenuti = rispostaBatch.Content .ReadAsMultipartAsync().Result.Contents; //Ognuno dei contenuti è l'HttpResponseMessage relativo ad una nostra //richiesta. In questo esempio, ci interessa esaminare solo l'ultima risposta, // quella relativa alla richiesta GET HttpResponseMessage rispostaTemperaturaMedia = contenuti.Last() .ReadAsHttpResponseMessageAsync().Result; //Il contenuto della risposta sarà una stringa JSON... string contenutoJson = rispostaTemperaturaMedia .Content.ReadAsStringAsync().Result; //...che deserializziamo in questo modo string temperaturaMedia = JsonConvert .DeserializeObject<string>(contenutoJson); //Il valore ottenuto possiamo usarlo in un messaggio da mostrare a video string messaggio = string.Format( "La media italiana è di {0}", temperaturaMedia);
Come si vede dall'esempio, siamo liberi di inserire nel batch varie richieste HTTP, siano esse GET, POST o di altro tipo.
L'interoperabilità è uno dei punti di forza di ASP.NET Web API, infatti l'utente non sarà in alcun modo costretto ad usare un client .NET ma potrà preparare la richiesta batch usando un linguaggio a sua scelta. L'importante è che il suo contenuto sia conforme alla specifica multipart/mixed (http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html), così come descritta dal W3C.
Ed ecco il contenuto grezzo della nostra richiesta batch: se lo esaminiamo, noteremo che ogni richiesta incapsulata al suo interno è stata ben isolata grazie ad un boundary che agisce da delimitatore.
POST http://localhost:56813/api/batch HTTP/1.1 Content-Type: multipart/mixed; boundary="bff10b16-941b-4128-b8c8-0e6589c475ed" Host: localhost:56813 Content-Length: 654 Expect: 100-continue Connection: Keep-Alive --bff10b16-941b-4128-b8c8-0e6589c475ed Content-Type: application/http; msgtype=request POST /api/temperature/roma HTTP/1.1 Host: localhost:56813 Content-Type: application/json; charset=utf-8 "15.5 °C" --bff10b16-941b-4128-b8c8-0e6589c475ed Content-Type: application/http; msgtype=request POST /api/temperature/milano HTTP/1.1 Host: localhost:56813 Content-Type: application/json; charset=utf-8 "12.7 °C" --bff10b16-941b-4128-b8c8-0e6589c475ed Content-Type: application/http; msgtype=request GET /api/temperature/italia/media HTTP/1.1 Host: localhost:56813 --bff10b16-941b-4128-b8c8-0e6589c475ed--
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Creare gruppi di client per Event Grid MQTT
Ottimizzazione dei block template in Angular 17
Miglioramenti nell'accessibilità con Angular CDK
Supporto ai tipi DateOnly e TimeOnly in Entity Framework Core
Cambiare la chiave di partizionamento di Azure Cosmos DB
Utilizzare database e servizi con gli add-on di Container App
Utilizzare politiche di resiliency con Azure Container App
Gestire la cancellazione di una richiesta in streaming da Blazor
Utilizzare i primary constructor di C# per inizializzare le proprietà
Utilizzare Tailwind CSS all'interno di React: primi componenti
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Code scanning e advanced security con Azure DevOps
I più letti di oggi
- Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Utilizzare il metodo CountBy di LINQ per semplificare raggruppamenti e i conteggi
- Creare una libreria CSS universale: Cards
- Eseguire script pre e post esecuzione di un workflow di GitHub