posts - 315, comments - 268, trackbacks - 15

My Links

News

View Pietro Libro's profile on LinkedIn

DomusDotNet
   DomusDotNet

Pietro Libro

Tag Cloud

Article Categories

Archives

Post Categories

Blogs amici

Links

Request Batching in Web Api 2

Una funzionalità molto interessante introdotta con ASP.NET Web API 2 OData è il supporto “Batching”, ovvero la possibilità di “impacchettare” in una singola richiesta HTTP piu’ richieste Web API (action) e ricevere in un’unica risposta HTTP i risultati ottenuti dalle singole invocazioni delle Web API. Questa funzionalità è molto interessante in quanto ci permette di minimizzare il numero di richieste\risposte tra client e server, riducendo il traffico di rete (pensiamo al Cloud…). 

Per abilitare Server Side questa funzionalità è necessario esporre tramite registrazione, un HTTP batch endpoint utilizzando il metodo MapHttpBatchRoute esposto dall’instanza Routes della classe HttpRouteCollection:

config.Routes.MapHttpBatchRoute(
        routeName: "BatchApi",
        routeTemplate: "api/batch",
        batchHandler: new System.Web.Http.Batch.DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer));

 

Il codice del Controller Web Api è relativamente semplice (è in allegato) ed è stato utilizzato come DEMO per la mia sessione durante l’ultimo l’evento organizzato da DomusDotNet. A questo punto la palla passa Client Side, dove tramite un’unica chiamata HTTP vogliamo ottenere l’elenco di tutte le entità Car serializzate, l’inserimento di una nuova entità Car e la modifica del valore di una proprietà di un’entità precedentemente recuperata.

Iniziamo con il recuperare l’entità Car con Id=1

HttpClient client = new HttpClient();
string response = await client.GetStringAsync("http://localhost:31613/Api/Cars/1");

Car car = (Newtonsoft.Json.JsonConvert.DeserializeObject(response)
    as Newtonsoft.Json.Linq.JObject).ToObject<Car>();

 

Poi un HttpRequestMessage per ottenere (GET) l’elenco di tutte le entità:

HttpRequestMessage getCars = new HttpRequestMessage(HttpMethod.Get, http://localhost:31613/Api/Cars);
 

Un altro HttpRequestMessage per aggiungere (POST) una nuova entità:

JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter();
HttpRequestMessage postCar = new HttpRequestMessage(HttpMethod.Post, "http://localhost:31613/Api/Cars");
postCar.Content = new ObjectContent<Car>(new Car()
{
    Brand_Id = 1,
    DailyRent = 50.0f,
    EngineSize = "2500",
    Model = "GTV",
    Note = "---"
},formatter);
 

Ed infine un HttpRequestMessage per aggiornare (PUT) l’entità Car precedentemente recuperata:

car.Note += " BATCH";
HttpRequestMessage putCar = new HttpRequestMessage(HttpMethod.Put,
    string.Format("http://localhost:31613/Api/Cars?id={0}", car.Id));
putCar.Content = new ObjectContent<dynamic>(car, formatter);
 

a questo punto, dobbiamo “impacchettare” le singole richieste in un’unica richiesta HTTP, utilizzanto un’istanza di MultiPartContent:

HttpMessageContent getCarsContent = new HttpMessageContent(getCars);
HttpMessageContent postCarContent = new HttpMessageContent(postCar);
HttpMessageContent putCarContent = new HttpMessageContent(putCar);

MultipartContent multiPartContent = new MultipartContent("mixed", "batch_" + Guid.NewGuid().ToString());
multiPartContent.Add(getCarsContent);
multiPartContent.Add(postCarContent);
multiPartContent.Add(putCarContent);

HttpRequestMessage batchRequest = new HttpRequestMessage(HttpMethod.Post, "http://localhost:31613/api/batch");
batchRequest.Content = multiPartContent;
 

Non ci resta che effettuare la richiesta al Server:

HttpResponseMessage multipartResponse = await client.SendAsync(batchRequest);
MultipartMemoryStreamProvider responseContents = await multipartResponse.Content.ReadAsMultipartAsync();
 

e recuperare le singole risposte:

////Status Code: 200, Ok.
HttpResponseMessage getResponse = await responseContents.Contents[0].ReadAsHttpResponseMessageAsync();
////Status Code: 201, Created.
HttpResponseMessage postResponse = await responseContents.Contents[1].ReadAsHttpResponseMessageAsync();
////Status Code:204, Not Content.
HttpResponseMessage putResponse = await responseContents.Contents[2].ReadAsHttpResponseMessageAsync();

 

Normalmente le singole richieste contenute all’interno di un “batch” sono eseguite sequenzialmente, di conseguenza in questo caso, la richiesta di POST partirebbe subito dopo quella di GET ed immediatamente prima di quella di PUT. Se l’ordine di esecuzione non è importante, possiamo eseguire le richieste in modo asincrono impostando la proprietà ExecutionOrder a BatchExecutionOrder.NonSequential:

config.Routes.MapHttpBatchRoute(
    routeName: "BatchApi",
    routeTemplate: "api/batch",
    batchHandler: new System.Web.Http.Batch.DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer)
    {
        ExecutionOrder = System.Web.Http.Batch.BatchExecutionOrder.NonSequential
    });
 

Print | posted on lunedì 23 dicembre 2013 13:49 | Filed Under [ C# .Net Framework 4.0 .Net Framework 4.5 ASP.NET Web Api ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET