/// <summary>
        /// Executes the operation.
        /// </summary>
        /// <param name="batchReader">The batch reader.</param>
        /// <param name="batchId">The batch id.</param>
        /// <param name="originalRequest">The original request containing all the batch requests.</param>
        /// <param name="handler">The handler for processing a message.</param>
        /// <returns>The response for the operation.</returns>
        public virtual async Task <ODataBatchResponseItem> ExecuteOperationAsync(ODataBatchReader batchReader, Guid batchId, HttpRequest originalRequest, RequestDelegate handler)
        {
            if (batchReader == null)
            {
                throw new ArgumentNullException(nameof(batchReader));
            }

            if (originalRequest == null)
            {
                throw new ArgumentNullException(nameof(originalRequest));
            }

            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            CancellationToken cancellationToken = originalRequest.HttpContext.RequestAborted;

            cancellationToken.ThrowIfCancellationRequested();
            HttpContext operationContext = await batchReader.ReadOperationRequestAsync(originalRequest.HttpContext, batchId, cancellationToken).ConfigureAwait(false);

            operationContext.Request.ClearRouteServices();
            OperationRequestItem operation = new OperationRequestItem(operationContext);

            ODataBatchResponseItem responseItem = await operation.SendRequestAsync(handler).ConfigureAwait(false);

            return(responseItem);
        }
        public virtual async Task <IList <ODataBatchResponseItem> > ExecuteRequestMessagesAsync(IEnumerable <ODataBatchRequestItem> requests, RequestDelegate handler)
        {
            if (requests == null)
            {
                throw new ArgumentNullException(nameof(requests));
            }

            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            IList <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();

            foreach (ODataBatchRequestItem request in requests)
            {
                ODataBatchResponseItem responseItem = await request.SendRequestAsync(handler).ConfigureAwait(false);

                responses.Add(responseItem);

                if (responseItem != null && responseItem.IsResponseSuccessful() == false && ContinueOnError == false)
                {
                    break;
                }
            }

            return(responses);
        }
        public override async Task ProcessBatchAsync(HttpContext context, RequestDelegate nextHandler)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (nextHandler == null)
            {
                throw new ArgumentNullException(nameof(nextHandler));
            }

            if (!await ValidateRequest(context.Request).ConfigureAwait(false))
            {
                return;
            }

            // This container is for the overall batch request.
            HttpRequest      request          = context.Request;
            IServiceProvider requestContainer = request.CreateRouteServices(PrefixName);

            requestContainer.GetRequiredService <ODataMessageReaderSettings>().BaseUri = GetBaseUri(request);

            // How to dispose it?
            ODataMessageReader reader = request.GetODataMessageReader(requestContainer);

            ODataBatchReader batchReader = await reader.CreateODataBatchReaderAsync().ConfigureAwait(false);

            List <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();
            Guid batchId = Guid.NewGuid();

            ODataOptions options = context.RequestServices.GetRequiredService <IOptions <ODataOptions> >().Value;
            bool         enableContinueOnErrorHeader = (options != null)
                ? options.EnableContinueOnErrorHeader
                : false;

            SetContinueOnError(request.Headers, enableContinueOnErrorHeader);

            while (await batchReader.ReadAsync().ConfigureAwait(false))
            {
                ODataBatchResponseItem responseItem = null;
                if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                {
                    responseItem = await ExecuteChangeSetAsync(batchReader, batchId, request, nextHandler).ConfigureAwait(false);
                }
                else if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    responseItem = await ExecuteOperationAsync(batchReader, batchId, request, nextHandler).ConfigureAwait(false);
                }
                if (responseItem != null)
                {
                    responses.Add(responseItem);
                    if (responseItem.IsResponseSuccessful() == false && ContinueOnError == false)
                    {
                        break;
                    }
                }
            }

            await CreateResponseMessageAsync(responses, request).ConfigureAwait(false);
        }