예제 #1
0
        public static async Task <IList <HttpRequestMessage> > ReadChangeSetRequestAsync(this ODataBatchReader reader, Guid batchId, CancellationToken cancellationToken)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("reader");
            }

            if (reader.State != ODataBatchReaderState.ChangesetStart)
            {
                throw Error.InvalidOperation(
                          SRResources.InvalidBatchReaderState,
                          reader.State.ToString(),
                          ODataBatchReaderState.ChangesetStart.ToString());
            }

            Guid changeSetId = Guid.NewGuid();
            List <HttpRequestMessage> requests = new List <HttpRequestMessage>();

            while (await reader.ReadAsync() && reader.State != ODataBatchReaderState.ChangesetEnd)
            {
                if (reader.State == ODataBatchReaderState.Operation)
                {
                    requests.Add(await ReadOperationInternalAsync(reader, batchId, changeSetId, cancellationToken));
                }
            }

            return(requests);
        }
예제 #2
0
        /// <summary>
        /// Reads a ChangeSet request.
        /// </summary>
        /// <param name="reader">The <see cref="ODataBatchReader"/>.</param>
        /// <param name="context">The context containing the batch request messages.</param>
        /// <param name="batchId">The Batch Id.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A collection of <see cref="HttpRequest"/> in the ChangeSet.</returns>
        public static async Task <IList <HttpContext> > ReadChangeSetRequestAsync(
            this ODataBatchReader reader, HttpContext context, Guid batchId, CancellationToken cancellationToken)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            if (reader.State != ODataBatchReaderState.ChangesetStart)
            {
                throw Error.InvalidOperation(
                          SRResources.InvalidBatchReaderState,
                          reader.State.ToString(),
                          ODataBatchReaderState.ChangesetStart.ToString());
            }

            Guid changeSetId            = Guid.NewGuid();
            List <HttpContext> contexts = new List <HttpContext>();

            while (await reader.ReadAsync().ConfigureAwait(false) && reader.State != ODataBatchReaderState.ChangesetEnd)
            {
                if (reader.State == ODataBatchReaderState.Operation)
                {
                    contexts.Add(await ReadOperationInternalAsync(reader, context, batchId, changeSetId, cancellationToken).ConfigureAwait(false));
                }
            }

            return(contexts);
        }
예제 #3
0
        /// <inheritdoc/>
        public override async Task ProcessBatchAsync(HttpContext context, RequestDelegate nextHandler)
        {
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }
            if (nextHandler == null)
            {
                throw Error.ArgumentNull("nextHandler");
            }

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

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

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

            ODataMessageReader reader = request.GetODataMessageReader(requestContainer);

            ODataBatchReader batchReader = await reader.CreateODataBatchReaderAsync();

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

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

            SetContinueOnError(new WebApiRequestHeaders(request.Headers), enableContinueOnErrorHeader);

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

            await CreateResponseMessageAsync(responses, request);
        }
예제 #4
0
        /// <summary>
        /// Executes the ChangeSet.
        /// </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="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>The response for the ChangeSet.</returns>
        public virtual async Task <ODataBatchResponseItem> ExecuteChangeSetAsync(ODataBatchReader batchReader, Guid batchId, HttpRequestMessage originalRequest, CancellationToken cancellationToken)
        {
            if (batchReader == null)
            {
                throw Error.ArgumentNull("batchReader");
            }
            if (originalRequest == null)
            {
                throw Error.ArgumentNull("originalRequest");
            }

            Guid changeSetId = Guid.NewGuid();
            List <HttpResponseMessage>  changeSetResponse          = new List <HttpResponseMessage>();
            Dictionary <string, string> contentIdToLocationMapping = new Dictionary <string, string>();

            try
            {
                while (await batchReader.ReadAsync() && batchReader.State != ODataBatchReaderState.ChangesetEnd)
                {
                    if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        HttpRequestMessage changeSetOperationRequest = await batchReader.ReadChangeSetOperationRequestAsync(batchId, changeSetId, bufferContentStream : false);

                        changeSetOperationRequest.CopyBatchRequestProperties(originalRequest);
                        changeSetOperationRequest.DeleteRequestContainer(false);
                        try
                        {
                            HttpResponseMessage response = await ODataBatchRequestItem.SendMessageAsync(Invoker, changeSetOperationRequest, cancellationToken, contentIdToLocationMapping);

                            if (response.IsSuccessStatusCode)
                            {
                                changeSetResponse.Add(response);
                            }
                            else
                            {
                                ChangeSetRequestItem.DisposeResponses(changeSetResponse);
                                changeSetResponse.Clear();
                                changeSetResponse.Add(response);
                                return(new ChangeSetResponseItem(changeSetResponse));
                            }
                        }
                        finally
                        {
                            originalRequest.RegisterForDispose(changeSetOperationRequest.GetResourcesForDisposal());
                            originalRequest.RegisterForDispose(changeSetOperationRequest);
                        }
                    }
                }
            }
            catch
            {
                ChangeSetRequestItem.DisposeResponses(changeSetResponse);
                throw;
            }

            return(new ChangeSetResponseItem(changeSetResponse));
        }
예제 #5
0
        /// <summary>
        /// Converts the incoming OData batch request into a collection of request messages.
        /// </summary>
        /// <param name="context">The context containing the batch request messages.</param>
        /// <returns>A collection of <see cref="ODataBatchRequestItem"/>.</returns>
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            HttpRequest      request          = context.Request;
            IServiceProvider requestContainer = request.CreateRouteServices(PrefixName);

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

            using (ODataMessageReader reader = request.GetODataMessageReader(requestContainer))
            {
                CancellationToken            cancellationToken = context.RequestAborted;
                List <ODataBatchRequestItem> requests          = new List <ODataBatchRequestItem>();
                ODataBatchReader             batchReader       = await reader.CreateODataBatchReaderAsync().ConfigureAwait(false);

                Guid batchId = Guid.NewGuid();
                Dictionary <string, string> contentToLocationMapping = new Dictionary <string, string>();

                while (await batchReader.ReadAsync().ConfigureAwait(false))
                {
                    if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                    {
                        IList <HttpContext> changeSetContexts = await batchReader.ReadChangeSetRequestAsync(context, batchId, cancellationToken).ConfigureAwait(false);

                        foreach (HttpContext changeSetContext in changeSetContexts)
                        {
                            changeSetContext.Request.ClearRouteServices();
                        }

                        ChangeSetRequestItem requestItem = new ChangeSetRequestItem(changeSetContexts);
                        requestItem.ContentIdToLocationMapping = contentToLocationMapping;
                        requests.Add(requestItem);
                    }
                    else if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        HttpContext operationContext = await batchReader.ReadOperationRequestAsync(context, batchId, cancellationToken).ConfigureAwait(false);

                        operationContext.Request.ClearRouteServices();
                        OperationRequestItem requestItem = new OperationRequestItem(operationContext);
                        requestItem.ContentIdToLocationMapping = contentToLocationMapping;
                        requests.Add(requestItem);
                    }
                }

                return(requests);
            }
        }
예제 #6
0
        public async Task ExecuteOperationAsync_CopiesPropertiesFromRequest_WithoutExcludedProperties()
        {
            // Arrange
            RequestDelegate handler = context =>
            {
                context.Features[typeof(UnbufferedODataBatchHandlerTest)] = "foo";
                return(Task.FromResult(context.Response));
            };

            UnbufferedODataBatchHandler batchHandler = new UnbufferedODataBatchHandler();
            string batchRequest = @"--75148e61-e67a-4bb7-ac0f-78fa30d0da30
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 318941389

GET / HTTP/1.1
Host: example.com


--75148e61-e67a-4bb7-ac0f-78fa30d0da30--
";

            HttpRequest request     = RequestFactory.Create("Post", "http://example.com/$batch", opt => opt.AddModel(EdmCoreModel.Instance));
            HttpContext httpContext = request.HttpContext;

            byte[] requestBytes = Encoding.UTF8.GetBytes(batchRequest);
            request.Body          = new MemoryStream(requestBytes);
            request.ContentType   = "multipart/mixed;boundary=\"75148e61-e67a-4bb7-ac0f-78fa30d0da30\"";
            request.ContentLength = 431;
            httpContext.ODataFeature().PrefixName = "";
            IServiceProvider sp = request.GetSubServiceProvider();

            IODataRequestMessage oDataRequestMessage = ODataMessageWrapperHelper.Create(httpContext.Request.Body, request.Headers, sp);
            ODataMessageReader   oDataMessageReader  = new ODataMessageReader(oDataRequestMessage, new ODataMessageReaderSettings {
                BaseUri = new Uri("http://example.com")
            });

            ODataBatchReader batchReader = await oDataMessageReader.CreateODataBatchReaderAsync();

            List <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();
            await batchReader.ReadAsync();

            // Act
            var response = await batchHandler.ExecuteOperationAsync(batchReader, Guid.NewGuid(), httpContext.Request, handler);

            // Assert
            OperationResponseItem operationResponseItem = Assert.IsType <OperationResponseItem>(response);

            Assert.Equal("foo", operationResponseItem.Context.Features[typeof(UnbufferedODataBatchHandlerTest)]);
        }
        public async Task ExecuteChangeSetAsync_CopiesPropertiesFromRequest_WithoutExcludedProperties()
        {
            MockHttpServer server = new MockHttpServer(request =>
            {
                return(new HttpResponseMessage
                {
                    RequestMessage = request
                });
            });
            UnbufferedODataBatchHandler batchHandler = new UnbufferedODataBatchHandler(server);
            HttpRequestMessage          batchRequest = new HttpRequestMessage(HttpMethod.Post, "http://example.com/$batch")
            {
                Content = new MultipartContent("mixed")
                {
                    new MultipartContent("mixed") // ChangeSet
                    {
                        ODataBatchRequestHelper.CreateODataRequestContent(new HttpRequestMessage(HttpMethod.Post, "http://example.com/values")
                        {
                            Content = new StringContent("foo")
                        })
                    }
                }
            };

            batchRequest.Properties.Add("foo", "bar");
            batchRequest.SetRouteData(new HttpRouteData(new HttpRoute()));
            batchRequest.RegisterForDispose(new StringContent(String.Empty));
            ODataMessageReader reader = await batchRequest.Content
                                        .GetODataMessageReaderAsync(new ODataMessageReaderSettings { BaseUri = new Uri("http://example.com") }, CancellationToken.None);

            ODataBatchReader batchReader = await reader.CreateODataBatchReaderAsync();

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

            var response = await batchHandler.ExecuteChangeSetAsync(batchReader, Guid.NewGuid(), batchRequest, CancellationToken.None);

            var changeSetResponses = ((ChangeSetResponseItem)response).Responses;

            foreach (var changeSetResponse in changeSetResponses)
            {
                var changeSetRequest = changeSetResponse.RequestMessage;
                Assert.Equal("bar", changeSetRequest.Properties["foo"]);
                Assert.Null(changeSetRequest.GetRouteData());
                Assert.Same(changeSetRequest, changeSetRequest.GetUrlHelper().Request);
                Assert.Empty(changeSetRequest.GetResourcesForDisposal());
            }
        }
        /// <summary>
        /// Executes the ChangeSet.
        /// </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 ChangeSet.</returns>
        public virtual async Task <ODataBatchResponseItem> ExecuteChangeSetAsync(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));
            }

            Guid changeSetId = Guid.NewGuid();
            List <HttpContext>          changeSetResponse          = new List <HttpContext>();
            Dictionary <string, string> contentIdToLocationMapping = new Dictionary <string, string>();

            while (await batchReader.ReadAsync().ConfigureAwait(false) && batchReader.State != ODataBatchReaderState.ChangesetEnd)
            {
                if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    CancellationToken cancellationToken         = originalRequest.HttpContext.RequestAborted;
                    HttpContext       changeSetOperationContext = await batchReader.ReadChangeSetOperationRequestAsync(originalRequest.HttpContext, batchId, changeSetId, cancellationToken).ConfigureAwait(false);

                    changeSetOperationContext.Request.CopyBatchRequestProperties(originalRequest);
                    //changeSetOperationContext.Request.DeleteRequestContainer(false);

                    await ODataBatchRequestItem.SendRequestAsync(handler, changeSetOperationContext, contentIdToLocationMapping).ConfigureAwait(false);

                    if (changeSetOperationContext.Response.IsSuccessStatusCode())
                    {
                        changeSetResponse.Add(changeSetOperationContext);
                    }
                    else
                    {
                        changeSetResponse.Clear();
                        changeSetResponse.Add(changeSetOperationContext);
                        return(new ChangeSetResponseItem(changeSetResponse));
                    }
                }
            }

            return(new ChangeSetResponseItem(changeSetResponse));
        }
        /// <summary>
        /// Converts the incoming OData batch request into a collection of request messages.
        /// </summary>
        /// <param name="context">The context containing the batch request messages.</param>
        /// <returns>A collection of <see cref="ODataBatchRequestItem"/>.</returns>
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            HttpRequest      request          = context.Request;
            IServiceProvider requestContainer = request.CreateSubServiceProvider(PrefixName);

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

            using (ODataMessageReader reader = request.GetODataMessageReader(requestContainer))
            {
                CancellationToken            cancellationToken = context.RequestAborted;
                List <ODataBatchRequestItem> requests          = new List <ODataBatchRequestItem>();
                ODataBatchReader             batchReader       = await reader.CreateODataBatchReaderAsync().ConfigureAwait(false);

                Guid batchId = Guid.NewGuid();
                while (await batchReader.ReadAsync().ConfigureAwait(false))
                {
                    if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                    {
                        IList <HttpContext> changeSetContexts = await batchReader.ReadChangeSetRequestAsync(context, batchId, cancellationToken).ConfigureAwait(false);

                        foreach (HttpContext changeSetContext in changeSetContexts)
                        {
                            changeSetContext.Request.CopyBatchRequestProperties(request);
                            changeSetContext.Request.DeleteSubRequestProvider(false);
                        }
                        requests.Add(new ChangeSetRequestItem(changeSetContexts));
                    }
                    else if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        HttpContext operationContext = await batchReader.ReadOperationRequestAsync(context, batchId, cancellationToken).ConfigureAwait(false);

                        operationContext.Request.CopyBatchRequestProperties(request);
                        operationContext.Request.DeleteSubRequestProvider(false);
                        requests.Add(new OperationRequestItem(operationContext));
                    }
                }

                return(requests);
            }
        }
예제 #10
0
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            IServiceProvider requestContainer = request.CreateRequestContainer(ODataRouteName);

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

            ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(requestContainer, cancellationToken);

            request.RegisterForDispose(reader);

            List <ODataBatchRequestItem> requests    = new List <ODataBatchRequestItem>();
            ODataBatchReader             batchReader = await reader.CreateODataBatchReaderAsync();

            Guid batchId = Guid.NewGuid();

            while (await batchReader.ReadAsync())
            {
                if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                {
                    IList <HttpRequestMessage> changeSetRequests = await batchReader.ReadChangeSetRequestAsync(batchId, cancellationToken);

                    foreach (HttpRequestMessage changeSetRequest in changeSetRequests)
                    {
                        changeSetRequest.CopyBatchRequestProperties(request);
                        changeSetRequest.DeleteRequestContainer(false);
                    }
                    requests.Add(new ChangeSetRequestItem(changeSetRequests));
                }
                else if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    HttpRequestMessage operationRequest = await batchReader.ReadOperationRequestAsync(batchId, bufferContentStream : true, cancellationToken : cancellationToken);

                    operationRequest.CopyBatchRequestProperties(request);
                    operationRequest.DeleteRequestContainer(false);
                    requests.Add(new OperationRequestItem(operationRequest));
                }
            }

            return(requests);
        }
예제 #11
0
        /// <inheritdoc/>
        public override async Task <HttpResponseMessage> ProcessBatchAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            ValidateRequest(request);

            // This container is for the overall batch request.
            IServiceProvider requestContainer = request.CreateRequestContainer(ODataRouteName);

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

            ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(requestContainer, cancellationToken);

            request.RegisterForDispose(reader);

            ODataBatchReader batchReader = await reader.CreateODataBatchReaderAsync();

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

            HttpConfiguration configuration  = request.GetConfiguration();
            bool enableContinueOnErrorHeader = (configuration != null)
                ? configuration.HasEnabledContinueOnErrorHeader()
                : false;

            SetContinueOnError(new WebApiRequestHeaders(request.Headers), enableContinueOnErrorHeader);

            try
            {
                while (await batchReader.ReadAsync())
                {
                    ODataBatchResponseItem responseItem = null;
                    if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                    {
                        responseItem = await ExecuteChangeSetAsync(batchReader, batchId, request, cancellationToken);
                    }
                    else if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        responseItem = await ExecuteOperationAsync(batchReader, batchId, request, cancellationToken);
                    }
                    if (responseItem != null)
                    {
                        responses.Add(responseItem);
                        if (responseItem.IsResponseSuccessful() == false && ContinueOnError == false)
                        {
                            break;
                        }
                    }
                }
            }
            catch
            {
                foreach (ODataBatchResponseItem response in responses)
                {
                    if (response != null)
                    {
                        response.Dispose();
                    }
                }
                throw;
            }

            return(await CreateResponseMessageAsync(responses, request, cancellationToken));
        }