Desde ASP.NET Web Api 2 tenemos la posibilidad de crear un endpoint batch en los servicios http que creamos. Esta característica nos da la posibilidad de agrupar en una sola petición http desde cliente múltiples peticiones http, de esta forma se reduce el tráfico desde cliente a servidor.
Vamos a ver como podemos habilitar esta característica y un ejemplo de uso.
Registrar batch enpoint
Para registrar este endpoint, nos vamos a la clase WebApiConfig que nos crea por defecto la plantilla de proyecto Web Api y añadimos una nueva ruta.config.Routes.MapHttpBatchRoute( routeName: "WebApiBatch", routeTemplate: "api/batch", batchHandler: new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer));
Fijaros que asignamos como BatchHandler un DefaultHttpBatchHandler, este handler será el que se encargará de recibir la petición http agrupada y trata cada petición de forma individual pero ya en servidor.
Podemos configurar este handler para que trate de forma secuencial o no las peticiones agrupadas. Tenemos que crearnos antes de registrar la ruta batch el handler y le asignamos la propiedad ExecutionOrder, donde le podemos indicar BatchExecutionOrder.NonSequential o BatchExecutionOrder.Sequential, siendo este último el valor por defecto.
HttpBatchHandler batchHandler = new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer) { ExecutionOrder = BatchExecutionOrder.Sequential }; config.Routes.MapHttpBatchRoute( routeName: "WebApiBatch", routeTemplate: "api/batch", batchHandler: batchHandler);
Para el que tenga curiosidad, podéis ver el código de DefaultHttpBatchHandler aquí.
Tenemos la opción de crearnos nuestro propio handler batch personalizado heredando de este y sobeescribir el método encargado de tratar cada petición o crear por ejemplo nuestros propios mensajes de respuesta para cada petición.
Ejemplo
Lo primero es registrar el endpoint batch como hemos visto antes.Creamos un controlador de usuarios con un método post para dar del alta usuarios.
public class UsersController : ApiController { public HttpResponseMessage Post([FromBody]string userName) { Debug.Write(string.Format("User {0} created",userName)); return Request.CreateResponse(HttpStatusCode.OK); } }
Ahora ya podemos desde cliente atacar al endpoint batch creandonos un HttpRequestMessage donde el contenido va a ser un MultipartContent que va a contener cada petición individual a realizar al servidor
string baseAddress = "http://localhost:7164"; HttpClient client = new HttpClient(); HttpRequestMessage batchRequest = new HttpRequestMessage(HttpMethod.Post, baseAddress + "/api/batch") { Content = new MultipartContent("mixed") { new HttpMessageContent(new HttpRequestMessage(HttpMethod.Post, baseAddress + "/api/users") { Content = new ObjectContent("Arya Stark", new JsonMediaTypeFormatter()) }), new HttpMessageContent(new HttpRequestMessage(HttpMethod.Post, baseAddress + "/api/users") { Content = new ObjectContent ("Daenerys Targaryen", new JsonMediaTypeFormatter()) }), } }; HttpResponseMessage batchResponse = client.SendAsync(batchRequest).Result; MultipartStreamProvider streamProvider = batchResponse.Content.ReadAsMultipartAsync().Result; foreach (var content in streamProvider.Contents) { HttpResponseMessage response = content.ReadAsHttpResponseMessageAsync().Result; Debug.WriteLine(response.StatusCode); }
Cuando nos llega la respuesta vamos a poder obtener la respuesta de cada petición que habiamos incluido en la petición batch.
Formatos raw
A continuación vamos a ver el formato raw de los mensajes entre servidor y cliente para el ejemplo que hemos visto.Formato de la petición
POST http://localhost:7164/api/batch HTTP/1.1 Content-Type: multipart/mixed; boundary="91731eeb-d443-4aa6-9816-560a8aca66b1" Connection: Keep-Alive Host: localhost:7164 Content-Length: 434 --91731eeb-d443-4aa6-9816-560a8aca66b1 Content-Type: application/http; msgtype=request POST /api/users HTTP/1.1 Host: localhost:7164 Content-Type: application/json; charset=utf-8 "Arya Stark" --91731eeb-d443-4aa6-9816-560a8aca66b1 Content-Type: application/http; msgtype=request POST /api/users HTTP/1.1 Host: localhost:7164 Content-Type: application/json; charset=utf-8 "Daenerys Targaryen" --91731eeb-d443-4aa6-9816-560a8aca66b1--
Formato de la respuesta
HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 268 Content-Type: multipart/mixed; boundary="bbee1acb-1bb0-4b3c-8c0c-8744672bb8a7" Expires: -1 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNceHVyeG9cRHJvcGJveFxEZXNhcnJvbGxvXFByb3llY3Rvc1BlcnNvbmFsZXNcWHVyeG9EZXZlbG9wZXIuQmxvZ3Nwb3RcV2ViQXBpQmF0Y2hcRXhhbXBsZVxXZWJBcGlCYXRjaEV4YW1wbGVcV2ViQXBpQmF0Y2hFeGFtcGxlXGFwaVxiYXRjaA==?= X-Powered-By: ASP.NET Date: Tue, 30 Sep 2014 21:04:35 GMT --bbee1acb-1bb0-4b3c-8c0c-8744672bb8a7 Content-Type: application/http; msgtype=response HTTP/1.1 200 OK --bbee1acb-1bb0-4b3c-8c0c-8744672bb8a7 Content-Type: application/http; msgtype=response HTTP/1.1 200 OK --bbee1acb-1bb0-4b3c-8c0c-8744672bb8a7--
Resumen
Hemos visto como poder añadir un endpoint batch a un servicio http usando Web Api. A nivel de servidor solo hay que registar la ruta batch porque el DefaultHttpBatchHandler se va a encargar de tratar esa petición batch ejecutando cada petición que trae en el contenido de forma individual.En cliente tenemos que crearnos una petición y en su contenido agrupar cada petición individual que queremos hacer al servidor.
Libros relacionados
ASP.NET Web API 2: Building a REST Service from Start to FinishDesigning Evolvable Web APIs with ASP.NET
ASP.NET Web API 2 Recipes: A Problem-Solution Approach
No hay comentarios:
Publicar un comentario