原文:Batching Handler for ASP.NET Web API
-
自定义实现
HttpMessageHandler
public class BatchHandler : HttpMessageHandler { HttpMessageInvoker _server; public BatchHandler(HttpConfiguration config) { _server = new HttpMessageInvoker(new HttpServer(config)); } protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { // Return 400 for the wrong MIME type if ("multipart/batch" != request.Content.Headers.ContentType.MediaType) { return request.CreateResponse(HttpStatusCode.BadRequest); } // Start a multipart response var outerContent = new MultipartContent("batch"); var outerResp = request.CreateResponse(); outerResp.Content = outerContent; // Read the multipart request var multipart = await request.Content.ReadAsMultipartAsync(); foreach (var httpContent in multipart.Contents) { HttpResponseMessage innerResp = null; try { // Decode the request object var innerReq = await httpContent.ReadAsHttpRequestMessageAsync(); // Send the request through the pipeline innerResp = await _server.SendAsync( innerReq, cancellationToken ); } catch (Exception) { // If exceptions are thrown, send back generic 400 innerResp = new HttpResponseMessage( HttpStatusCode.BadRequest ); } // Wrap the response in a message content and put it // into the multipart response outerContent.Add(new HttpMessageContent(innerResp)); } return outerResp; } }
-
配置Web Api config
var batchHandler = new BatchHandler(config); config.Routes.MapHttpRoute("batch", "api/batch", null, null, batchHandler); config.Routes.MapHttpRoute("default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
-
模拟请求
var client = new HttpClient(); var batchRequest = new HttpRequestMessage( HttpMethod.Post, "http://localhost/api/batch" ); var batchContent = new MultipartContent("batch"); batchRequest.Content = batchContent; batchContent.Add( new HttpMessageContent( new HttpRequestMessage( HttpMethod.Get, "http://localhost/api/values" ) ) ); batchContent.Add( new HttpMessageContent( new HttpRequestMessage( HttpMethod.Get, "http://localhost/foo/bar" ) ) ); batchContent.Add( new HttpMessageContent( new HttpRequestMessage( HttpMethod.Get, "http://localhost/api/values/1" ) ) ); using (Stream stdout = Console.OpenStandardOutput()) { Console.WriteLine("<<< REQUEST >>>"); Console.WriteLine(); Console.WriteLine(batchRequest); Console.WriteLine(); batchContent.CopyToAsync(stdout).Wait(); Console.WriteLine(); var batchResponse = client.SendAsync(batchRequest).Result; Console.WriteLine("<<< RESPONSE >>>"); Console.WriteLine(); Console.WriteLine(batchResponse); Console.WriteLine(); batchResponse.Content.CopyToAsync(stdout).Wait(); Console.WriteLine(); Console.WriteLine(); }
结果如下:
<<< REQUEST >>>
Method: POST,
RequestUri: 'http://localhost/api/batch',
Version: 1.1,
Content: System.Net.Http.MultipartContent,
Headers:
{
Content-Type: multipart/batch; boundary="3bc5bd67-3517-4cd0-bcdd-9d23f3850402"
}
--3bc5bd67-3517-4cd0-bcdd-9d23f3850402
Content-Type: application/http; msgtype=request
GET /api/values HTTP/1.1
Host: localhost
--3bc5bd67-3517-4cd0-bcdd-9d23f3850402
Content-Type: application/http; msgtype=request
GET /foo/bar HTTP/1.1
Host: localhost
--3bc5bd67-3517-4cd0-bcdd-9d23f3850402--
<<< RESPONSE >>>
StatusCode: 200,
ReasonPhrase: 'OK',
Version: 1.1,
Content: System.Net.Http.StreamContent,
Headers:
{
Pragma: no-cache
Cache-Control: no-cache
Date: Thu, 21 Jun 2012 00:21:40 GMT
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Content-Length: 658
Content-Type: multipart/batch
Expires: -1
}
--3d1ba137-ea6a-40d9-8e34-1b8812394baa
Content-Type: application/http; msgtype=response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
["Hello","world!"]
--3d1ba137-ea6a-40d9-8e34-1b8812394baa
Content-Type: application/http; msgtype=response
HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/foo/bar'."}
--3d1ba137-ea6a-40d9-8e34-1b8812394baa
Content-Type: application/http; msgtype=response