// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Diagnostics; using System.Diagnostics.Contracts; using System.Net; using System.Net.Http; using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Web.Http.ExceptionHandling; using System.Web.Http.Hosting; namespace System.Web.Http.Batch { /// /// Defines the abstraction for handling HTTP batch requests. /// // Class Hierarchy // - HttpBatchHandler // - DefaultHttpBatchHandler // - ODataBatchHandler // - DefaultODataBatchHandler // - UnbufferedODataBatchHandler public abstract class HttpBatchHandler : HttpMessageHandler { private readonly HttpServer _server; /// /// Initializes a new instance of the class. /// /// The for handling the individual batch requests. protected HttpBatchHandler(HttpServer httpServer) { if (httpServer == null) { throw Error.ArgumentNull("httpServer"); } _server = httpServer; Invoker = new HttpMessageInvoker(httpServer); } /// /// Gets the invoker to send the batch requests to the . /// public HttpMessageInvoker Invoker { get; private set; } /// This property is internal and settable only for unit testing purposes. internal IExceptionLogger ExceptionLogger { get { return _server.ExceptionLogger; } set { _server.ExceptionLogger = value; } } /// This property is internal and settable only for unit testing purposes. internal IExceptionHandler ExceptionHandler { get { return _server.ExceptionHandler; } set { _server.ExceptionHandler = value; } } /// protected sealed override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw Error.ArgumentNull("request"); } request.Properties[HttpPropertyKeys.IsBatchRequest] = true; ExceptionDispatchInfo exceptionInfo; try { return await ProcessBatchAsync(request, cancellationToken); } catch (OperationCanceledException) { // Propogate the canceled task without calling exception loggers or handlers. throw; } catch (HttpResponseException httpResponseException) { return httpResponseException.Response; } catch (Exception exception) { exceptionInfo = ExceptionDispatchInfo.Capture(exception); } Debug.Assert(exceptionInfo.SourceException != null); ExceptionContext exceptionContext = new ExceptionContext(exceptionInfo.SourceException, ExceptionCatchBlocks.HttpBatchHandler, request); await ExceptionLogger.LogAsync(exceptionContext, cancellationToken); HttpResponseMessage response = await ExceptionHandler.HandleAsync(exceptionContext, cancellationToken); if (response == null) { exceptionInfo.Throw(); } return response; } /// /// Processes the incoming batch request as a single . /// /// The batch request. /// The token to monitor for cancellation requests. /// The batch response. public abstract Task ProcessBatchAsync(HttpRequestMessage request, CancellationToken cancellationToken); } }