Пример #1
0
        private async Task <ODataResponse> ReadResponse(ODataBatchReader odataReader)
        {
            var batch = new List <ODataResponse>();

            while (odataReader.Read())
            {
                switch (odataReader.State)
                {
                case ODataBatchReaderState.ChangesetStart:
                    break;

                case ODataBatchReaderState.Operation:
                    var operationMessage = odataReader.CreateOperationResponseMessage();
                    if (operationMessage.StatusCode == (int)HttpStatusCode.NoContent)
                    {
                        batch.Add(ODataResponse.FromStatusCode(operationMessage.StatusCode));
                    }
                    else if (operationMessage.StatusCode >= (int)HttpStatusCode.BadRequest)
                    {
                        batch.Add(ODataResponse.FromStatusCode(
                                      operationMessage.StatusCode,
#if SILVERLIGHT
                                      operationMessage.GetStream()));
                    }
#else
                                      await operationMessage.GetStreamAsync().ConfigureAwait(false)));
#endif
                    else
                    {
                        batch.Add(await GetResponseAsync(operationMessage).ConfigureAwait(false));
                    }
                    break;
Пример #2
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 (reader.Read() && reader.State != ODataBatchReaderState.ChangesetEnd)
            {
                if (reader.State == ODataBatchReaderState.Operation)
                {
                    requests.Add(await ReadOperationInternalAsync(reader, batchId, changeSetId, cancellationToken));
                }
            }
            return(requests);
        }
        private async Task <ODataResponse> ReadResponse(ODataBatchReader odataReader)
        {
            var batch = new List <ODataResponse>();

            while (odataReader.Read())
            {
                switch (odataReader.State)
                {
                case ODataBatchReaderState.ChangesetStart:
                    break;

                case ODataBatchReaderState.Operation:
                    var operationMessage = odataReader.CreateOperationResponseMessage();
                    if (operationMessage.StatusCode == (int)HttpStatusCode.NoContent)
                    {
                        batch.Add(ODataResponse.FromStatusCode(operationMessage.StatusCode));
                    }
                    else
                    {
                        batch.Add(await GetResponseAsync(operationMessage));
                    }
                    break;

                case ODataBatchReaderState.ChangesetEnd:
                    break;
                }
            }

            return(ODataResponse.FromBatch(batch));
        }
Пример #4
0
        private bool ReadBatch(string requestPayload, ODataVersion version)
        {
            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(requestPayload))
            };

            requestMessage.SetHeader("Content-Type", batchContentTypeMultipartMime);
            ODataMessageReaderSettings settings = new ODataMessageReaderSettings {
                Version = version
            };

            using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, settings, this.userModel))
            {
                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        // Encountered an operation (either top-level or in a change set)
                        ODataBatchOperationRequestMessage operationMessage =
                            batchReader.CreateOperationRequestMessage();
                        break;
                    }
                }
            }

            return(true);
        }
Пример #5
0
        /// <inheritdoc/>
        public override async Task <HttpResponseMessage> ProcessBatchAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            ValidateRequest(request);

            ODataMessageReaderSettings oDataReaderSettings = new ODataMessageReaderSettings
            {
                DisableMessageStreamDisposal = true,
                MessageQuotas = MessageQuotas,
                BaseUri       = GetBaseUri(request)
            };

            cancellationToken.ThrowIfCancellationRequested();
            ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(oDataReaderSettings);

            request.RegisterForDispose(reader);

            ODataBatchReader batchReader            = reader.CreateODataBatchReader();
            List <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();
            Guid batchId = Guid.NewGuid();
            List <IDisposable> resourcesToDispose = new List <IDisposable>();

            try
            {
                while (batchReader.Read())
                {
                    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);
                    }
                }
            }
            catch
            {
                foreach (ODataBatchResponseItem response in responses)
                {
                    if (response != null)
                    {
                        response.Dispose();
                    }
                }
                throw;
            }

            return(await CreateResponseMessageAsync(responses, request, cancellationToken));
        }
Пример #6
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            = reader.CreateODataBatchReader();
            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 (batchReader.Read())
            {
                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);
        }
Пример #7
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 (batchReader.Read() && 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));
        }
Пример #8
0
        /// <summary>
        /// Asynchronously parses the batch requests.
        /// </summary>
        /// <param name="request">The HTTP request that contains the batch requests.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public override async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (this.ApiFactory == null)
            {
                throw new InvalidOperationException(Resources.BatchHandlerRequiresApiContextFactory);
            }

            Ensure.NotNull(request, "request");

            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings
            {
                DisableMessageStreamDisposal = true,
                MessageQuotas = MessageQuotas,
                BaseUri       = GetBaseUri(request)
            };

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

            request.RegisterForDispose(reader);

            List <ODataBatchRequestItem> requests    = new List <ODataBatchRequestItem>();
            ODataBatchReader             batchReader = reader.CreateODataBatchReader();
            Guid batchId = Guid.NewGuid();

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

                    foreach (HttpRequestMessage changeSetRequest in changeSetRequests)
                    {
                        changeSetRequest.CopyBatchRequestProperties(request);
                    }

                    requests.Add(this.CreateChangeSetRequestItem(changeSetRequests));
                }
                else if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    HttpRequestMessage operationRequest = await batchReader.ReadOperationRequestAsync(
                        batchId,
                        bufferContentStream : true,
                        cancellationToken : cancellationToken);

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

            return(requests);
        }
Пример #9
0
        public void 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 = batchRequest.Content
                                        .GetODataMessageReaderAsync(new ODataMessageReaderSettings {
                BaseUri = new Uri("http://example.com")
            }, CancellationToken.None)
                                        .Result;
            ODataBatchReader batchReader            = reader.CreateODataBatchReader();
            List <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();
            Guid batchId = Guid.NewGuid();

            batchReader.Read();

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

            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());
            }
        }
Пример #10
0
        public static OeBatchMessage CreateBatchMessage(OeMessageContext context, Stream requestStream, String contentType)
        {
            IODataRequestMessage requestMessage = new OeInMemoryMessage(requestStream, contentType);
            var settings = new ODataMessageReaderSettings()
            {
                EnableMessageStreamDisposal = false
            };

            using (var messageReader = new ODataMessageReader(requestMessage, settings))
            {
                var batchMessage             = new List <OeBatchMessage>();
                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                    {
                        var operations = new List <OeOperationMessage>();
                        while (batchReader.Read() && batchReader.State != ODataBatchReaderState.ChangesetEnd)
                        {
                            if (batchReader.State == ODataBatchReaderState.Operation)
                            {
                                OeOperationMessage operation = OeOperationMessage.Create(context, batchReader);
                                operations.Add(operation);
                            }
                        }
                        return(new OeBatchMessage(contentType, operations));
                    }
                    else if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        OeOperationMessage operation = OeOperationMessage.Create(context, batchReader);
                        return(new OeBatchMessage(contentType, operation));
                    }
                }
            }

            throw new InvalidOperationException("batch not found");
        }
Пример #11
0
        /// <summary>
        /// Asynchronously parses the batch requests.
        /// </summary>
        /// <param name="request">The HTTP request that contains the batch requests.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task object that represents this asynchronous operation.</returns>
        public override async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            Ensure.NotNull(request, "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 = reader.CreateODataBatchReader();
            Guid batchId = Guid.NewGuid();

            while (batchReader.Read())
            {
                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(this.CreateRestierBatchChangeSetRequestItem(changeSetRequests));
                }
                else if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    HttpRequestMessage operationRequest = await batchReader.ReadOperationRequestAsync(
                        batchId, true, cancellationToken);

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

            return(requests);
        }
Пример #12
0
        private void ClientReadSingletonBatchResponse(byte[] responsePayload, string batchContentType)
        {
            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

            responseMessage.SetHeader("Content-Type", batchContentType);
            using (ODataMessageReader messageReader = new ODataMessageReader(responseMessage, new ODataMessageReaderSettings(), this.userModel))
            {
                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        // Encountered an operation (either top-level or in a change set)
                        ODataBatchOperationResponseMessage operationMessage = batchReader.CreateOperationResponseMessage();
                        if (operationMessage.StatusCode == 200)
                        {
                            using (ODataMessageReader innerMessageReader = new ODataMessageReader(operationMessage, new ODataMessageReaderSettings(), this.userModel))
                            {
                                ODataReader reader = innerMessageReader.CreateODataResourceReader();

                                while (reader.Read())
                                {
                                    if (reader.State == ODataReaderState.ResourceEnd)
                                    {
                                        ODataResource entry = reader.Item as ODataResource;
                                        Assert.Equal(10, entry.Properties.Single(p => p.Name == "WebId").Value);
                                        Assert.Equal("WebSingleton", entry.Properties.Single(p => p.Name == "Name").Value);
                                    }
                                }
                            }

                            // The only two messages with HTTP-200 response codes are the two GET requests with content id value of null.
                            // Verify that: for multipart batch the content id of the response is matching that of the request;
                            // for Json batch the content id of the response is not null.
                            Assert.True(
                                (batchReader is ODataJsonLightBatchReader && operationMessage.ContentId != null) ||
                                (batchReader is ODataMultipartMixedBatchReader && operationMessage.ContentId == null));
                        }
                        break;
                    }
                }
            }
        }
Пример #13
0
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            ODataMessageReaderSettings oDataReaderSettings = new ODataMessageReaderSettings
            {
                DisableMessageStreamDisposal = true,
                MessageQuotas = MessageQuotas,
                BaseUri       = GetBaseUri(request)
            };

            cancellationToken.ThrowIfCancellationRequested();
            ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(oDataReaderSettings);

            request.RegisterForDispose(reader);

            List <ODataBatchRequestItem> requests    = new List <ODataBatchRequestItem>();
            ODataBatchReader             batchReader = reader.CreateODataBatchReader();
            Guid batchId = Guid.NewGuid();

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

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

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

            return(requests);
        }
Пример #14
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="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 Error.ArgumentNull("batchReader");
            }
            if (originalRequest == null)
            {
                throw Error.ArgumentNull("originalRequest");
            }
            if (handler == null)
            {
                throw Error.ArgumentNull("handler");
            }

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

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

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

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

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

            return(new ChangeSetResponseItem(changeSetResponse));
        }
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            HttpRequest      request          = context.Request;
            IServiceProvider requestContainer = request.CreateRequestContainer(ODataRouteName);

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

            ODataMessageReader reader = request.GetODataMessageReader(requestContainer);

            CancellationToken            cancellationToken = context.RequestAborted;
            List <ODataBatchRequestItem> requests          = new List <ODataBatchRequestItem>();
            ODataBatchReader             batchReader       = reader.CreateODataBatchReader();
            Guid batchId = Guid.NewGuid();

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

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

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

            return(requests);
        }
        private void ClientReadBatchResponse(byte[] responsePayload, BodyContentType bodyContentType)
        {
            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

            responseMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson);
            using (ODataMessageReader messageReader = new ODataMessageReader(responseMessage, new ODataMessageReaderSettings(), null))
            {
                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        // Encountered an operation (either top-level or in a change set)
                        ODataBatchOperationResponseMessage operationMessage = batchReader.CreateOperationResponseMessage();
                        if (operationMessage.StatusCode == 200)
                        {
                            using (Stream operationMessageBody = operationMessage.GetStream())
                            {
                                // Verify the bytes in the response body.
                                byte[] sampleBytes = bodyContentType == BodyContentType.Textual
                                        ? Encoding.UTF8.GetBytes("\"" + this.textualSampleStringB + "\"")
                                        : this.binarySampleBytesB;

                                Assert.Equal(operationMessageBody.Length, sampleBytes.Length);
                                foreach (byte samplebyte in sampleBytes)
                                {
                                    Assert.Equal(samplebyte, operationMessageBody.ReadByte());
                                }
                            }
                        }
                        else
                        {
                            Assert.True(201 == operationMessage.StatusCode);
                        }
                        break;
                    }
                }
            }
        }
Пример #17
0
        private async Task <ODataResponse> ReadResponse(ODataBatchReader odataReader)
        {
            var batch = new List <ODataResponse>();

            while (odataReader.Read())
            {
                switch (odataReader.State)
                {
                case ODataBatchReaderState.ChangesetStart:
                    break;

                case ODataBatchReaderState.Operation:
                    var operationMessage = odataReader.CreateOperationResponseMessage();
                    if (operationMessage.StatusCode == (int)HttpStatusCode.NoContent)
                    {
                        batch.Add(ODataResponse.FromStatusCode(TypeCache, operationMessage.StatusCode, operationMessage.Headers));
                    }
                    else if (operationMessage.StatusCode >= (int)HttpStatusCode.BadRequest)
                    {
                        batch.Add(ODataResponse.FromStatusCode(TypeCache,
                                                               operationMessage.StatusCode,
                                                               operationMessage.Headers,
                                                               await operationMessage.GetStreamAsync().ConfigureAwait(false),
                                                               _session.Settings.WebRequestExceptionMessageSource));
                    }
                    else
                    {
                        batch.Add(await GetResponseAsync(operationMessage).ConfigureAwait(false));
                    }

                    break;

                case ODataBatchReaderState.ChangesetEnd:
                    break;
                }
            }

            return(ODataResponse.FromBatch(TypeCache, batch));
        }
        private void ServiceProcessBatchRequest(ODataJsonBatchPayloadTestCase testCase, ODataVersion version)
        {
            string requestPayload = testCase.RequestPayload;

            ODataJsonBatchPayloadTestCase.ValidateContentType requestMessageContentTypeVerifier = testCase.ContentTypeVerifier;

            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(Encoding.ASCII.GetBytes(requestPayload))
            };

            requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);

            using (ODataMessageReader messageReader =
                       new ODataMessageReader(requestMessage, new ODataMessageReaderSettings()
            {
                Version = version, BaseUri = new Uri("http://odata.org")
            }, this.edmModel))
            {
                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();

                int operationIdx = 0;
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage();

                        // Verify operation message content type processing.
                        requestMessageContentTypeVerifier.Invoke(operationMessage, operationIdx);

                        operationIdx++;
                        break;
                    }
                }
            }
        }
        public virtual async Task <IList <ODataBatchRequestItem> > ParseBatchRequestsAsync(HttpRequestMessage request)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            ODataMessageReaderSettings oDataReaderSettings = new ODataMessageReaderSettings
            {
                DisableMessageStreamDisposal = true,
                MessageQuotas = MessageQuotas,
                BaseUri       = GetBaseUri(request)
            };

            ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(oDataReaderSettings);

            request.RegisterForDispose(reader);

            List <ODataBatchRequestItem> requests    = new List <ODataBatchRequestItem>();
            ODataBatchReader             batchReader = reader.CreateODataBatchReader();
            Guid batchId = Guid.NewGuid();

            while (batchReader.Read())
            {
                if (batchReader.State == ODataBatchReaderState.ChangesetStart)
                {
                    requests.Add(new ChangeSetRequestItem(await batchReader.ReadChangeSetRequestAsync(batchId)));
                }
                else if (batchReader.State == ODataBatchReaderState.Operation)
                {
                    requests.Add(new OperationRequestItem(await batchReader.ReadOperationRequestAsync(batchId, bufferContentStream: true)));
                }
            }

            return(requests);
        }
        internal static IList <TableResult> TableBatchOperationPostProcess(IList <TableResult> result, TableBatchOperation batch, RESTCommand <IList <TableResult> > cmd, HttpWebResponse resp, OperationContext ctx, TableRequestOptions options, string accountName)
        {
            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings();

            readerSettings.MessageQuotas = new ODataMessageQuotas()
            {
                MaxPartsPerBatch = TableConstants.TableServiceMaxResults, MaxReceivedMessageSize = TableConstants.TableServiceMaxPayload
            };

            using (ODataMessageReader responseReader = new ODataMessageReader(new HttpResponseAdapterMessage(resp, cmd.ResponseStream), readerSettings))
            {
                // create a reader
                ODataBatchReader reader = responseReader.CreateODataBatchReader();

                // Initial => changesetstart
                if (reader.State == ODataBatchReaderState.Initial)
                {
                    reader.Read();
                }

                if (reader.State == ODataBatchReaderState.ChangesetStart)
                {
                    // ChangeSetStart => Operation
                    reader.Read();
                }

                int  index          = 0;
                bool failError      = false;
                bool failUnexpected = false;

                while (reader.State == ODataBatchReaderState.Operation)
                {
                    TableOperation currentOperation = batch[index];
                    TableResult    currentResult    = new TableResult()
                    {
                        Result = currentOperation.Entity
                    };
                    result.Add(currentResult);

                    ODataBatchOperationResponseMessage mimePartResponseMessage = reader.CreateOperationResponseMessage();
                    string contentType = mimePartResponseMessage.GetHeader(Constants.ContentTypeElement);

                    currentResult.HttpStatusCode = mimePartResponseMessage.StatusCode;

                    // Validate Status Code.
                    if (currentOperation.OperationType == TableOperationType.Insert)
                    {
                        failError = mimePartResponseMessage.StatusCode == (int)HttpStatusCode.Conflict;
                        if (currentOperation.EchoContent)
                        {
                            failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.Created;
                        }
                        else
                        {
                            failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.NoContent;
                        }
                    }
                    else if (currentOperation.OperationType == TableOperationType.Retrieve)
                    {
                        if (mimePartResponseMessage.StatusCode == (int)HttpStatusCode.NotFound)
                        {
                            index++;

                            // Operation => next
                            reader.Read();
                            continue;
                        }

                        failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.OK;
                    }
                    else
                    {
                        failError      = mimePartResponseMessage.StatusCode == (int)HttpStatusCode.NotFound;
                        failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.NoContent;
                    }

                    if (failError)
                    {
                        // If the parse error is null, then don't get the extended error information and the StorageException will contain SR.ExtendedErrorUnavailable message.
                        if (cmd.ParseError != null)
                        {
                            cmd.CurrentResult.ExtendedErrorInformation = cmd.ParseError(mimePartResponseMessage.GetStream(), resp, contentType);
                        }

                        cmd.CurrentResult.HttpStatusCode = mimePartResponseMessage.StatusCode;
                        if (!string.IsNullOrEmpty(cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage))
                        {
                            string msg = cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage;
                            cmd.CurrentResult.HttpStatusMessage = msg.Substring(0, msg.IndexOf("\n", StringComparison.Ordinal));
                        }
                        else
                        {
                            cmd.CurrentResult.HttpStatusMessage = mimePartResponseMessage.StatusCode.ToString(CultureInfo.InvariantCulture);
                        }

                        throw new StorageException(
                                  cmd.CurrentResult,
                                  cmd.CurrentResult.ExtendedErrorInformation != null ? cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage : SR.ExtendedErrorUnavailable,
                                  null)
                              {
                                  IsRetryable = false
                              };
                    }

                    if (failUnexpected)
                    {
                        // If the parse error is null, then don't get the extended error information and the StorageException will contain SR.ExtendedErrorUnavailable message.
                        if (cmd.ParseError != null)
                        {
                            cmd.CurrentResult.ExtendedErrorInformation = cmd.ParseError(mimePartResponseMessage.GetStream(), resp, contentType);
                        }

                        cmd.CurrentResult.HttpStatusCode = mimePartResponseMessage.StatusCode;
                        if (!string.IsNullOrEmpty(cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage))
                        {
                            string msg = cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage;
                            cmd.CurrentResult.HttpStatusMessage = msg.Substring(0, msg.IndexOf("\n", StringComparison.Ordinal));
                        }
                        else
                        {
                            cmd.CurrentResult.HttpStatusMessage = mimePartResponseMessage.StatusCode.ToString(CultureInfo.InvariantCulture);
                        }

                        string indexString = Convert.ToString(index, CultureInfo.InvariantCulture);

                        // Attempt to extract index of failing entity from extended error info
                        if (cmd.CurrentResult.ExtendedErrorInformation != null &&
                            !string.IsNullOrEmpty(cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage))
                        {
                            string tempIndex = TableRequest.ExtractEntityIndexFromExtendedErrorInformation(cmd.CurrentResult);
                            if (!string.IsNullOrEmpty(tempIndex))
                            {
                                indexString = tempIndex;
                            }
                        }

                        throw new StorageException(cmd.CurrentResult, string.Format(CultureInfo.CurrentCulture, SR.BatchErrorInOperation, indexString), null)
                              {
                                  IsRetryable = true
                              };
                    }

                    // Update etag
                    if (!string.IsNullOrEmpty(mimePartResponseMessage.GetHeader(Constants.HeaderConstants.EtagHeader)))
                    {
                        currentResult.Etag = mimePartResponseMessage.GetHeader(Constants.HeaderConstants.EtagHeader);

                        if (currentOperation.Entity != null)
                        {
                            currentOperation.Entity.ETag = currentResult.Etag;
                        }
                    }

                    // Parse Entity if needed
                    if (currentOperation.OperationType == TableOperationType.Retrieve || (currentOperation.OperationType == TableOperationType.Insert && currentOperation.EchoContent))
                    {
                        if (mimePartResponseMessage.GetHeader(Constants.ContentTypeElement).Contains(Constants.JsonNoMetadataAcceptHeaderValue))
                        {
                            ReadEntityUsingJsonParser(currentResult, currentOperation, mimePartResponseMessage.GetStream(), ctx, options);
                        }
                        else
                        {
                            ReadOdataEntity(currentResult, currentOperation, mimePartResponseMessage, ctx, readerSettings, accountName, options);
                        }
                    }
                    else if (currentOperation.OperationType == TableOperationType.Insert)
                    {
                        currentOperation.Entity.Timestamp = ParseETagForTimestamp(currentResult.Etag);
                    }

                    index++;

                    // Operation =>
                    reader.Read();
                }
            }

            return(result);
        }
Пример #21
0
        /// <inheritdoc/>
        public override async Task <HttpResponseMessage> ProcessBatchAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            ValidateRequest(request);

            ODataMessageReaderSettings oDataReaderSettings = new ODataMessageReaderSettings
            {
                DisableMessageStreamDisposal = true,
                MessageQuotas = MessageQuotas,
                BaseUri       = GetBaseUri(request)
            };

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

            request.RegisterForDispose(reader);

            ODataBatchReader batchReader            = reader.CreateODataBatchReader();
            List <ODataBatchResponseItem> responses = new List <ODataBatchResponseItem>();
            Guid batchId = Guid.NewGuid();
            List <IDisposable> resourcesToDispose = new List <IDisposable>();

            string preferHeader = RequestPreferenceHelpers.GetRequestPreferHeader(request);

            if ((preferHeader != null && preferHeader.Contains(PreferenceContinueOnError)) || (!request.GetConfiguration().HasEnabledContinueOnErrorHeader()))
            {
                ContinueOnError = true;
            }
            else
            {
                ContinueOnError = false;
            }
            try
            {
                while (batchReader.Read())
                {
                    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));
        }
Пример #22
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            = reader.CreateODataBatchReader();
            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 (batchReader.Read())
                {
                    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));
        }
Пример #23
0
        private IEnumerable <OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
        {
            if (this.batchMessageReader == null)
            {
                goto Label_056D;
            }
            bool iteratorVariable0 = false;
            bool iteratorVariable1 = false;
            int  index             = 0;
            int  iteratorVariable3 = 0;

            this.entryIndex = 0;
            Label_PostSwitchInIterator :;
            while (batchReader.Read())
            {
                Exception iteratorVariable4;
                switch (batchReader.State)
                {
                case ODataBatchReaderState.Operation:
                {
                    iteratorVariable4 = this.ProcessCurrentOperationResponse(batchReader);
                    if (iteratorVariable1)
                    {
                        break;
                    }
                    QueryOperationResponse iteratorVariable5 = null;
                    try
                    {
                        if (iteratorVariable4 == null)
                        {
                            DataServiceRequest query   = this.Queries[index];
                            MaterializeAtom    results = DataServiceRequest.Materialize(this.RequestInfo.GetDeserializationInfo(null), query.QueryComponents(this.RequestInfo.MaxProtocolVersion), null, this.currentOperationResponse.GetHeader("Content-Type"), this.currentOperationResponse.CreateResponseMessage(), query.PayloadKind);
                            iteratorVariable5 = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, results);
                        }
                    }
                    catch (ArgumentException exception)
                    {
                        iteratorVariable4 = exception;
                    }
                    catch (FormatException exception2)
                    {
                        iteratorVariable4 = exception2;
                    }
                    catch (InvalidOperationException exception3)
                    {
                        iteratorVariable4 = exception3;
                    }
                    if (iteratorVariable5 == null)
                    {
                        if (this.Queries == null)
                        {
                            throw iteratorVariable4;
                        }
                        DataServiceRequest request2 = this.Queries[index];
                        if (this.RequestInfo.IgnoreResourceNotFoundException && (this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound))
                        {
                            iteratorVariable5 = QueryOperationResponse.GetInstance(request2.ElementType, this.currentOperationResponse.Headers, request2, MaterializeAtom.EmptyResults);
                        }
                        else
                        {
                            iteratorVariable5       = QueryOperationResponse.GetInstance(request2.ElementType, this.currentOperationResponse.Headers, request2, MaterializeAtom.EmptyResults);
                            iteratorVariable5.Error = iteratorVariable4;
                        }
                    }
                    iteratorVariable5.StatusCode = (int)this.currentOperationResponse.StatusCode;
                    index++;
                    yield return(iteratorVariable5);

                    goto Label_PostSwitchInIterator;
                }

                case ODataBatchReaderState.ChangesetStart:
                {
                    if ((this.IsBatch && iteratorVariable0) || (iteratorVariable3 != 0))
                    {
                        System.Data.Services.Client.Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                    }
                    iteratorVariable1 = true;
                    continue;
                }

                case ODataBatchReaderState.ChangesetEnd:
                {
                    iteratorVariable0 = true;
                    iteratorVariable3 = 0;
                    iteratorVariable1 = false;
                    continue;
                }

                default:
                    goto Label_0491;
                }
                this.entryIndex = this.ValidateContentID(this.currentOperationResponse.Headers);
                try
                {
                    Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                    iteratorVariable3 += this.SaveResultProcessed(descriptor);
                    if (iteratorVariable4 != null)
                    {
                        throw iteratorVariable4;
                    }
                    this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
                    this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
                }
                catch (Exception exception4)
                {
                    this.ChangedEntries[this.entryIndex].SaveError = exception4;
                    iteratorVariable4 = exception4;
                    if (!CommonUtil.IsCatchableExceptionType(exception4))
                    {
                        throw;
                    }
                }
                ChangeOperationResponse iteratorVariable6 = new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex])
                {
                    StatusCode = (int)this.currentOperationResponse.StatusCode
                };
                if (iteratorVariable4 != null)
                {
                    iteratorVariable6.Error = iteratorVariable4;
                }
                iteratorVariable3++;
                this.entryIndex++;
                yield return(iteratorVariable6);

                goto Label_PostSwitchInIterator;
Label_0491:
                System.Data.Services.Client.Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
            }
            if (((this.Queries == null) && ((!iteratorVariable0 || (0 < index)) || (this.ChangedEntries.Any <Descriptor>(o => (o.ContentGeneratedForSave && (o.SaveResultWasProcessed == 0))) && (!this.IsBatch || (this.ChangedEntries.FirstOrDefault <Descriptor>(o => (o.SaveError != null)) == null))))) || ((this.Queries != null) && (index != this.Queries.Length)))
            {
                throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Batch_IncompleteResponseCount);
            }
Label_056D:
            yield break;
        }
Пример #24
0
        private byte[] ServiceReadRequestAndWriterResponseForMultipartBatchVerifyDependsOnIds(string requestPayload, ODataVersion maxVersion)
        {
            byte[] responseBytes = null;

            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(requestPayload))
            };

            requestMessage.SetHeader("Content-Type", batchContentTypeMultipartMime);
            ODataMessageReaderSettings settings = new ODataMessageReaderSettings {
                Version = maxVersion
            };

            using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, settings, this.userModel))
            {
                MemoryStream responseStream = new MemoryStream();

                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

                // Client is expected to receive the response message in the same format as that is used in the request sent.
                responseMessage.SetHeader("Content-Type", batchContentTypeMultipartMime);
                using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage))
                {
                    ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                    batchWriter.WriteStartBatch();

                    ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                    while (batchReader.Read())
                    {
                        switch (batchReader.State)
                        {
                        case ODataBatchReaderState.Operation:
                            // Encountered an operation (either top-level or in a change set)
                            ODataBatchOperationRequestMessage operationMessage =
                                batchReader.CreateOperationRequestMessage();

                            // Verify DependsOnIds are set correctly
                            IEnumerable <string> dependsOnIds = operationMessage.DependsOnIds;
                            switch (operationMessage.ContentId)
                            {
                            case "1":
                            case "2A":
                                Assert.True(dependsOnIds.Count() == 0);
                                break;

                            case "2B":
                                Assert.True(dependsOnIds.SequenceEqual(new List <string> {
                                    "2A"
                                }));
                                break;

                            case "2C":
                                Assert.True(dependsOnIds.SequenceEqual(new List <string> {
                                    "2A", "2B"
                                }));
                                break;

                            case "3":
                                Assert.True(dependsOnIds.SequenceEqual(new List <string> {
                                    "1"
                                }));
                                break;

                            default:
                                break;
                            }

                            ODataBatchOperationResponseMessage response =
                                batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);
                            if (operationMessage.Method == "PATCH")
                            {
                                response.StatusCode = 204;
                                response.SetHeader("Content-Type", "application/json;odata.metadata=none");
                            }
                            else if (operationMessage.Method == "PUT")
                            {
                                response.StatusCode = 201;
                                response.SetHeader("Content-Type", "application/json;");
                            }

                            break;

                        case ODataBatchReaderState.ChangesetStart:
                            batchWriter.WriteStartChangeset();
                            break;

                        case ODataBatchReaderState.ChangesetEnd:
                            batchWriter.WriteEndChangeset();
                            break;
                        }
                    }

                    batchWriter.WriteEndBatch();

                    responseStream.Position = 0;
                    responseBytes           = responseStream.ToArray();
                }

                return(responseBytes);
            }
        }
Пример #25
0
 private IEnumerable<OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
 {
     if (this.batchMessageReader == null)
     {
         goto Label_056D;
     }
     bool iteratorVariable0 = false;
     bool iteratorVariable1 = false;
     int index = 0;
     int iteratorVariable3 = 0;
     this.entryIndex = 0;
 Label_PostSwitchInIterator:;
     while (batchReader.Read())
     {
         Exception iteratorVariable4;
         switch (batchReader.State)
         {
             case ODataBatchReaderState.Operation:
             {
                 iteratorVariable4 = this.ProcessCurrentOperationResponse(batchReader);
                 if (iteratorVariable1)
                 {
                     break;
                 }
                 QueryOperationResponse iteratorVariable5 = null;
                 try
                 {
                     if (iteratorVariable4 == null)
                     {
                         DataServiceRequest query = this.Queries[index];
                         MaterializeAtom results = DataServiceRequest.Materialize(this.RequestInfo.GetDeserializationInfo(null), query.QueryComponents(this.RequestInfo.MaxProtocolVersion), null, this.currentOperationResponse.GetHeader("Content-Type"), this.currentOperationResponse.CreateResponseMessage(), query.PayloadKind);
                         iteratorVariable5 = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, results);
                     }
                 }
                 catch (ArgumentException exception)
                 {
                     iteratorVariable4 = exception;
                 }
                 catch (FormatException exception2)
                 {
                     iteratorVariable4 = exception2;
                 }
                 catch (InvalidOperationException exception3)
                 {
                     iteratorVariable4 = exception3;
                 }
                 if (iteratorVariable5 == null)
                 {
                     if (this.Queries == null)
                     {
                         throw iteratorVariable4;
                     }
                     DataServiceRequest request2 = this.Queries[index];
                     if (this.RequestInfo.IgnoreResourceNotFoundException && (this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound))
                     {
                         iteratorVariable5 = QueryOperationResponse.GetInstance(request2.ElementType, this.currentOperationResponse.Headers, request2, MaterializeAtom.EmptyResults);
                     }
                     else
                     {
                         iteratorVariable5 = QueryOperationResponse.GetInstance(request2.ElementType, this.currentOperationResponse.Headers, request2, MaterializeAtom.EmptyResults);
                         iteratorVariable5.Error = iteratorVariable4;
                     }
                 }
                 iteratorVariable5.StatusCode = (int) this.currentOperationResponse.StatusCode;
                 index++;
                 yield return iteratorVariable5;
                 goto Label_PostSwitchInIterator;
             }
             case ODataBatchReaderState.ChangesetStart:
             {
                 if ((this.IsBatch && iteratorVariable0) || (iteratorVariable3 != 0))
                 {
                     System.Data.Services.Client.Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                 }
                 iteratorVariable1 = true;
                 continue;
             }
             case ODataBatchReaderState.ChangesetEnd:
             {
                 iteratorVariable0 = true;
                 iteratorVariable3 = 0;
                 iteratorVariable1 = false;
                 continue;
             }
             default:
                 goto Label_0491;
         }
         this.entryIndex = this.ValidateContentID(this.currentOperationResponse.Headers);
         try
         {
             Descriptor descriptor = this.ChangedEntries[this.entryIndex];
             iteratorVariable3 += this.SaveResultProcessed(descriptor);
             if (iteratorVariable4 != null)
             {
                 throw iteratorVariable4;
             }
             this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
             this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
         }
         catch (Exception exception4)
         {
             this.ChangedEntries[this.entryIndex].SaveError = exception4;
             iteratorVariable4 = exception4;
             if (!CommonUtil.IsCatchableExceptionType(exception4))
             {
                 throw;
             }
         }
         ChangeOperationResponse iteratorVariable6 = new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]) {
             StatusCode = (int) this.currentOperationResponse.StatusCode
         };
         if (iteratorVariable4 != null)
         {
             iteratorVariable6.Error = iteratorVariable4;
         }
         iteratorVariable3++;
         this.entryIndex++;
         yield return iteratorVariable6;
         goto Label_PostSwitchInIterator;
     Label_0491:
         System.Data.Services.Client.Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
     }
     if (((this.Queries == null) && ((!iteratorVariable0 || (0 < index)) || (this.ChangedEntries.Any<Descriptor>(o => (o.ContentGeneratedForSave && (o.SaveResultWasProcessed == 0))) && (!this.IsBatch || (this.ChangedEntries.FirstOrDefault<Descriptor>(o => (o.SaveError != null)) == null))))) || ((this.Queries != null) && (index != this.Queries.Length)))
     {
         throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Batch_IncompleteResponseCount);
     }
 Label_056D:
     yield break;
 }
        private async Task<ODataResponse> ReadResponse(ODataBatchReader odataReader)
        {
            var batch = new List<ODataResponse>();

            while (odataReader.Read())
            {
                switch (odataReader.State)
                {
                    case ODataBatchReaderState.ChangesetStart:
                        break;
                    case ODataBatchReaderState.Operation:
                        var operationMessage = odataReader.CreateOperationResponseMessage();
                        if (operationMessage.StatusCode == (int)HttpStatusCode.NoContent)
                            batch.Add(ODataResponse.FromStatusCode(operationMessage.StatusCode));
                        else
                            batch.Add(await GetResponseAsync(operationMessage));
                        break;
                    case ODataBatchReaderState.ChangesetEnd:
                        break;
                }
            }

            return ODataResponse.FromBatch(batch);
        }
        /// <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 (batchReader.Read() && batchReader.State != ODataBatchReaderState.ChangesetEnd)
                {
                    if (batchReader.State == ODataBatchReaderState.Operation)
                    {
                        HttpRequestMessage changeSetOperationRequest = await batchReader.ReadChangeSetOperationRequestAsync(batchId, changeSetId, bufferContentStream: false);
                        changeSetOperationRequest.CopyBatchRequestProperties(originalRequest);
                        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);
        }
Пример #28
0
        internal static IList <TableResult> TableBatchOperationPostProcess(IList <TableResult> result, TableBatchOperation batch, RESTCommand <IList <TableResult> > cmd, HttpWebResponse resp, OperationContext ctx)
        {
            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings();

            readerSettings.MessageQuotas = new ODataMessageQuotas()
            {
                MaxPartsPerBatch = TableConstants.TableServiceMaxResults, MaxReceivedMessageSize = TableConstants.TableServiceMaxPayload
            };

            using (ODataMessageReader responseReader = new ODataMessageReader(new HttpResponseAdapterMessage(resp, cmd.ResponseStream), readerSettings))
            {
                // create a reader
                ODataBatchReader reader = responseReader.CreateODataBatchReader();

                // Initial => changesetstart
                if (reader.State == ODataBatchReaderState.Initial)
                {
                    reader.Read();
                }

                if (reader.State == ODataBatchReaderState.ChangesetStart)
                {
                    // ChangeSetStart => Operation
                    reader.Read();
                }

                int  index          = 0;
                bool failError      = false;
                bool failUnexpected = false;

                while (reader.State == ODataBatchReaderState.Operation)
                {
                    TableOperation currentOperation = batch[index];
                    TableResult    currentResult    = new TableResult()
                    {
                        Result = currentOperation.Entity
                    };
                    result.Add(currentResult);

                    ODataBatchOperationResponseMessage mimePartResponseMessage = reader.CreateOperationResponseMessage();
                    currentResult.HttpStatusCode = mimePartResponseMessage.StatusCode;

                    // Validate Status Code
                    if (currentOperation.OperationType == TableOperationType.Insert)
                    {
                        failError      = mimePartResponseMessage.StatusCode == (int)HttpStatusCode.Conflict;
                        failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.Created;
                    }
                    else if (currentOperation.OperationType == TableOperationType.Retrieve)
                    {
                        if (mimePartResponseMessage.StatusCode == (int)HttpStatusCode.NotFound)
                        {
                            index++;

                            // Operation => next
                            reader.Read();
                            continue;
                        }

                        failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.OK;
                    }
                    else
                    {
                        failError      = mimePartResponseMessage.StatusCode == (int)HttpStatusCode.NotFound;
                        failUnexpected = mimePartResponseMessage.StatusCode != (int)HttpStatusCode.NoContent;
                    }

                    if (failError)
                    {
                        cmd.CurrentResult.ExtendedErrorInformation = StorageExtendedErrorInformation.ReadFromStream(mimePartResponseMessage.GetStream());
                        cmd.CurrentResult.HttpStatusCode           = mimePartResponseMessage.StatusCode;

                        throw new StorageException(
                                  cmd.CurrentResult,
                                  cmd.CurrentResult.ExtendedErrorInformation != null ? cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage : SR.ExtendedErrorUnavailable,
                                  null)
                              {
                                  IsRetryable = false
                              };
                    }

                    if (failUnexpected)
                    {
                        cmd.CurrentResult.ExtendedErrorInformation = StorageExtendedErrorInformation.ReadFromStream(mimePartResponseMessage.GetStream());
                        cmd.CurrentResult.HttpStatusCode           = mimePartResponseMessage.StatusCode;

                        string indexString = Convert.ToString(index);

                        // Attempt to extract index of failing entity from extended error info
                        if (cmd.CurrentResult.ExtendedErrorInformation != null &&
                            !string.IsNullOrEmpty(cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage))
                        {
                            string tempIndex = TableRequest.ExtractEntityIndexFromExtendedErrorInformation(cmd.CurrentResult);
                            if (!string.IsNullOrEmpty(tempIndex))
                            {
                                indexString = tempIndex;
                            }
                        }

                        throw new StorageException(cmd.CurrentResult, SR.UnexpectedResponseCodeForOperation + indexString, null)
                              {
                                  IsRetryable = true
                              };
                    }

                    // Update etag
                    if (!string.IsNullOrEmpty(mimePartResponseMessage.GetHeader("ETag")))
                    {
                        currentResult.Etag = mimePartResponseMessage.GetHeader("ETag");

                        if (currentOperation.Entity != null)
                        {
                            currentOperation.Entity.ETag = currentResult.Etag;
                        }
                    }

                    // Parse Entity if needed
                    if (currentOperation.OperationType == TableOperationType.Retrieve || currentOperation.OperationType == TableOperationType.Insert)
                    {
                        ReadOdataEntity(currentResult, currentOperation, mimePartResponseMessage, ctx, readerSettings);
                    }

                    index++;

                    // Operation =>
                    reader.Read();
                }
            }

            return(result);
        }
        private byte[] ServiceReadSingletonBatchRequestAndWriterBatchResponse(ODataJsonBatchPayloadTestCase testCase, ODataVersion version)
        {
            string requestPayload = testCase.RequestPayload;
            Action <ODataBatchOperationRequestMessage, IList <string> > requestOpMessageVerifier = testCase.RequestMessageDependsOnIdVerifier;

            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(Encoding.ASCII.GetBytes(requestPayload))
            };

            requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);

            MemoryStream responseStream = new MemoryStream();

            using (ODataMessageReader messageReader =
                       new ODataMessageReader(requestMessage, new ODataMessageReaderSettings()
            {
                Version = version
            }, this.edmModel))
            {
                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

                // Client is expected to receive the response message in the same format as that is used in the request sent.
                responseMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);

                ODataMessageWriterSettings settings = new ODataMessageWriterSettings()
                {
                    Version = version
                };
                settings.SetServiceDocumentUri(new Uri(serviceDocumentUri));

                ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, settings, null);
                int operationIdx = 0;

                ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        // Encountered an operation (either top-level or in a change set)
                        ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage();

                        // Verify operation message if applicable.
                        requestOpMessageVerifier?.Invoke(operationMessage, testCase.ListOfDependsOnIds.ElementAt(operationIdx));

                        if (operationMessage.Method == "POST")
                        {
                            ODataBatchOperationResponseMessage response = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);
                            response.StatusCode = 201;
                            response.SetHeader("Content-Type", batchContentTypeApplicationJson);
                        }
                        else if (operationMessage.Method == "GET")
                        {
                            ODataBatchOperationResponseMessage response = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);
                            response.StatusCode = 200;
                            response.SetHeader("Content-Type", batchContentTypeApplicationJson);

                            using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(response, settings, this.edmModel))
                            {
                                ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(this.singleton,
                                                                                                           this.userType);
                                ODataResource entry = new ODataResource()
                                {
                                    TypeName   = "NS.User",
                                    Properties =
                                        new[]
                                    {
                                        new ODataProperty()
                                        {
                                            Name = "UserPrincipalName", Value = "*****@*****.**"
                                        },
                                        new ODataProperty()
                                        {
                                            Name = "GivenName", Value = "Jon"
                                        }
                                    }
                                };
                                entryWriter.WriteStart(entry);
                                entryWriter.WriteEnd();
                            }
                        }

                        operationIdx++;
                        break;

                    case ODataBatchReaderState.ChangesetStart:
                        batchWriter.WriteStartChangeset();
                        break;

                    case ODataBatchReaderState.ChangesetEnd:
                        batchWriter.WriteEndChangeset();
                        break;
                    }
                }

                batchWriter.WriteEndBatch();
            }

            responseStream.Position = 0;
            return(responseStream.ToArray());
        }
Пример #30
0
        private byte[] ServiceReadReferenceUriBatchRequestAndWriteResponse(byte[] requestPayload)
        {
            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(requestPayload)
            };

            requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);
            ODataMessageReaderSettings settings = new ODataMessageReaderSettings();

            settings.BaseUri = new Uri(serviceDocumentUri);

            byte[] responseBytes = null;

            using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, settings, this.userModel))
            {
                MemoryStream responseStream = new MemoryStream();

                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

                // Client is expected to receive the response message in the same format as that is used in the request sent.
                responseMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);

                using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage))
                {
                    ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                    batchWriter.WriteStartBatch();

                    ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                    while (batchReader.Read())
                    {
                        switch (batchReader.State)
                        {
                        case ODataBatchReaderState.Operation:
                            // Encountered an operation (either top-level or in a change set)
                            ODataBatchOperationRequestMessage operationMessage =
                                batchReader.CreateOperationRequestMessage();

                            ODataBatchOperationResponseMessage response =
                                batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);

                            if (operationMessage.Method == "PUT")
                            {
                                using (ODataMessageReader operationMessageReader = new ODataMessageReader(
                                           operationMessage, new ODataMessageReaderSettings(), this.userModel))
                                {
                                    ODataReader reader = operationMessageReader.CreateODataResourceReader();
                                    Assert.NotNull(reader);
                                }

                                response.StatusCode = 201;
                                response.SetHeader("Content-Type", "application/json;odata.metadata=none");
                            }
                            else if (operationMessage.Method == "PATCH")
                            {
                                using (ODataMessageReader operationMessageReader = new ODataMessageReader(
                                           operationMessage, new ODataMessageReaderSettings(), this.userModel))
                                {
                                    ODataReader reader = operationMessageReader.CreateODataResourceReader();
                                    Assert.NotNull(reader);
                                }

                                response.StatusCode = 204;
                            }
                            else if (operationMessage.Method == "GET")
                            {
                                response.StatusCode = 200;
                                response.SetHeader("Content-Type", "application/json;");
                                ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings();
                                writerSettings.ODataUri.ServiceRoot = new Uri(serviceDocumentUri);
                                using (
                                    ODataMessageWriter operationMessageWriter = new ODataMessageWriter(response,
                                                                                                       writerSettings, this.userModel))
                                {
                                    ODataWriter entryWriter =
                                        operationMessageWriter.CreateODataResourceWriter(this.singleton,
                                                                                         this.webType);
                                    ODataResource entry = new ODataResource()
                                    {
                                        TypeName   = "NS.Web",
                                        Properties = new[]
                                        {
                                            new ODataProperty()
                                            {
                                                Name = "WebId", Value = -1
                                            },
                                            new ODataProperty()
                                            {
                                                Name = "Name", Value = aVeryLongString
                                            }
                                        }
                                    };
                                    entryWriter.WriteStart(entry);
                                    entryWriter.WriteEnd();
                                }
                            }

                            break;

                        case ODataBatchReaderState.ChangesetStart:
                            // Set the group Id on the writer side to correlate with request.
                            string atomicGroupId = batchReader.CurrentGroupId;
                            batchWriter.WriteStartChangeset(atomicGroupId);
                            break;

                        case ODataBatchReaderState.ChangesetEnd:
                            batchWriter.WriteEndChangeset();
                            break;
                        }
                    }

                    batchWriter.WriteEndBatch();

                    responseStream.Position = 0;
                    responseBytes           = responseStream.ToArray();
                }

                return(responseBytes);
            }
        }
        private byte[] ServiceReadBatchRequestAndWriterBatchResponse(byte[] requestPayload, BodyContentType bodyContentType)
        {
            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(requestPayload)
            };

            requestMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson);

            using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, new ODataMessageReaderSettings(), null))
            {
                MemoryStream responseStream = new MemoryStream();

                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

                // Client is expected to receive the response message in the same format as that is used in the request sent.
                responseMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson);
                ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage);
                ODataBatchWriter   batchWriter   = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                ODataBatchReader batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:

                        ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage();

                        if (operationMessage.Method == "PUT")
                        {
                            using (Stream operationMessageBodyStream = operationMessage.GetStream())
                            {
                                // Verify the bytes in the request operation stream.
                                byte[] sampleBytes = bodyContentType == BodyContentType.Textual
                                        ? Encoding.UTF8.GetBytes("\"" + this.textualSampleStringA + "\"")
                                        : binarySampleBytesA;
                                Assert.Equal(operationMessageBodyStream.Length, sampleBytes.Length);
                                foreach (byte samplebyte in sampleBytes)
                                {
                                    Assert.Equal(samplebyte, operationMessageBodyStream.ReadByte());
                                }
                            }

                            // Create the response.
                            ODataBatchOperationResponseMessage operationResponse = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);
                            operationResponse.StatusCode = 201;
                            operationResponse.SetHeader("CoNtEnT-TyPe", "application/json;odata.metadata=none");
                        }
                        else if (operationMessage.Method == "GET")
                        {
                            ODataBatchOperationResponseMessage operationResponse = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId);
                            operationResponse.StatusCode = 200;
                            operationResponse.SetHeader("CoNtEnT-TyPe", GetContentType(bodyContentType));
                            ODataMessageWriterSettings settings = new ODataMessageWriterSettings();
                            settings.SetServiceDocumentUri(new Uri(serviceDocumentUri));
                            using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(operationResponse, settings, null))
                            {
                                operationMessageWriter.WriteValue(GetEncodedContentObject(bodyContentType, false));
                            }
                        }

                        break;

                    case ODataBatchReaderState.ChangesetStart:
                        batchWriter.WriteStartChangeset();
                        break;

                    case ODataBatchReaderState.ChangesetEnd:
                        batchWriter.WriteEndChangeset();
                        break;
                    }
                }

                batchWriter.WriteEndBatch();
                responseStream.Position = 0;
                return(responseStream.ToArray());
            }
        }
Пример #32
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <param name="batchReader">The batch reader to use for reading the batch response.</param>
        /// <returns>enumerable of QueryResponse or null</returns>
        /// <remarks>
        /// The batch message reader for the entire batch response is stored in this.batchMessageReader.
        /// Note that this method takes over the ownership of this reader and must Dispose it if it successfully returns.
        /// </remarks>
        private IEnumerable <OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
        {
            try
            {
                if (this.batchMessageReader == null)
                {
                    // The enumerable returned by this method can be enumerated multiple times.
                    // In that case it looks like if the method is called multiple times.
                    // This didn't fail in previous versions, it simply returned no results, so we need to do the same.
                    yield break;
                }

                Debug.Assert(batchReader != null, "batchReader != null");

                bool changesetFound  = false;
                bool insideChangeset = false;
                int  queryCount      = 0;
                int  operationCount  = 0;
                this.entryIndex = 0;
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                        #region ChangesetStart
                    case ODataBatchReaderState.ChangesetStart:
                        if ((Util.IsBatchWithSingleChangeset(this.Options) && changesetFound) || (operationCount != 0))
                        {
                            // Throw if we encounter multiple changesets when running in batch with single changeset mode
                            // or if we encounter operations outside of a changeset.
                            Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                        }

                        insideChangeset = true;
                        break;
                        #endregion

                        #region ChangesetEnd
                    case ODataBatchReaderState.ChangesetEnd:
                        changesetFound  = true;
                        operationCount  = 0;
                        insideChangeset = false;
                        break;
                        #endregion

                        #region Operation
                    case ODataBatchReaderState.Operation:
                        Exception exception = this.ProcessCurrentOperationResponse(batchReader, insideChangeset);
                        if (!insideChangeset)
                        {
                            #region Get response
                            Debug.Assert(operationCount == 0, "missing an EndChangeSet 2");

                            QueryOperationResponse qresponse = null;
                            try
                            {
                                if (exception == null)
                                {
                                    DataServiceRequest query        = this.Queries[queryCount];
                                    ResponseInfo       responseInfo = this.RequestInfo.GetDeserializationInfo(null /*mergeOption*/);
                                    MaterializeAtom    materializer = DataServiceRequest.Materialize(
                                        responseInfo,
                                        query.QueryComponents(this.RequestInfo.Model),
                                        null,
                                        this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                        this.currentOperationResponse.CreateResponseMessage(),
                                        query.PayloadKind);
                                    qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                }
                            }
                            catch (ArgumentException e)
                            {
                                exception = e;
                            }
                            catch (FormatException e)
                            {
                                exception = e;
                            }
                            catch (InvalidOperationException e)
                            {
                                exception = e;
                            }

                            if (qresponse == null)
                            {
                                if (this.Queries != null)
                                {
                                    // this is the normal ExecuteBatch response
                                    DataServiceRequest query = this.Queries[queryCount];

                                    if (this.RequestInfo.IgnoreResourceNotFoundException && this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound)
                                    {
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                    }
                                    else
                                    {
                                        qresponse       = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                        qresponse.Error = exception;
                                    }
                                }
                                else
                                {
                                    // This is top-level failure for SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) or SaveChanges(SaveChangesOptions.BatchWithIndependentOperations) operations.
                                    // example: server doesn't support batching or number of batch objects exceeded an allowed limit.
                                    // ex could be null if the server responded to SaveChanges with an unexpected success with
                                    // response of batched GETS that did not correspond the original POST/PATCH/PUT/DELETE requests.
                                    // we expect non-null since server should have failed with a non-success code
                                    // and HandleResponse(status, ...) should generate the exception object
                                    throw exception;
                                }
                            }

                            qresponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                            queryCount++;
                            yield return(qresponse);

                            #endregion
                        }
                        else
                        {
                            #region Update response
                            try
                            {
                                Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                                operationCount += this.SaveResultProcessed(descriptor);

                                if (exception != null)
                                {
                                    throw exception;
                                }

                                this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
#if DEBUG
                                this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers, this.currentOperationResponse.StatusCode);
#else
                                this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
#endif
                            }
                            catch (Exception e)
                            {
                                this.ChangedEntries[this.entryIndex].SaveError = e;
                                exception = e;

                                if (!CommonUtil.IsCatchableExceptionType(e))
                                {
                                    throw;
                                }
                            }

                            ChangeOperationResponse changeOperationResponse =
                                new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]);
                            changeOperationResponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                            if (exception != null)
                            {
                                changeOperationResponse.Error = exception;
                            }

                            operationCount++;
                            this.entryIndex++;
                            yield return(changeOperationResponse);

                            #endregion
                        }

                        break;
                        #endregion

                    default:
                        Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
                        break;
                    }
                }

                Debug.Assert(batchReader.State == ODataBatchReaderState.Completed, "unexpected batch state");

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if ((this.Queries == null &&
                     (!changesetFound ||
                      0 < queryCount ||
                      this.ChangedEntries.Any(o => o.ContentGeneratedForSave && o.SaveResultWasProcessed == 0) &&
                      (!this.IsBatchRequest || this.ChangedEntries.FirstOrDefault(o => o.SaveError != null) == null))) ||
                    (this.Queries != null && queryCount != this.Queries.Length))
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
            }
            finally
            {
                // Note that this will be called only once the enumeration of all responses is finished and the Dispose
                // was called on the IEnumerator used for that enumeration. It is not called when the method returns,
                // since the compiler change this method to return the compiler-generated IEnumerable.
                Util.Dispose(ref this.batchMessageReader);
            }
        }
Пример #33
0
        /// <summary>
        /// process the batch response
        /// </summary>
        /// <param name="batchReader">The batch reader to use for reading the batch response.</param>
        /// <returns>enumerable of QueryResponse or null</returns>
        /// <remarks>
        /// The batch message reader for the entire batch response is stored in this.batchMessageReader.
        /// Note that this method takes over the ownership of this reader and must Dispose it if it successfully returns.
        /// </remarks>
        private IEnumerable<OperationResponse> HandleBatchResponse(ODataBatchReader batchReader)
        {
            try
            {
                if (this.batchMessageReader == null)
                {
                    // The enumerable returned by this method can be enumerated multiple times.
                    // In that case it looks like if the method is called multiple times.
                    // This didn't fail in previous versions, it simply returned no results, so we need to do the same.
                    yield break;
                }

                Debug.Assert(batchReader != null, "batchReader != null");

                bool changesetFound = false;
                bool insideChangeset = false;
                int queryCount = 0;
                int operationCount = 0;
                this.entryIndex = 0;
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                        #region ChangesetStart
                        case ODataBatchReaderState.ChangesetStart:
                            if ((Util.IsBatchWithSingleChangeset(this.Options) && changesetFound) || (operationCount != 0))
                            {
                                // Throw if we encounter multiple changesets when running in batch with single changeset mode 
                                // or if we encounter operations outside of a changeset.
                                Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet);
                            }

                            insideChangeset = true;
                            break;
                        #endregion

                        #region ChangesetEnd
                        case ODataBatchReaderState.ChangesetEnd:
                            changesetFound = true;
                            operationCount = 0;
                            insideChangeset = false;
                            break;
                        #endregion

                        #region Operation
                        case ODataBatchReaderState.Operation:
                            Exception exception = this.ProcessCurrentOperationResponse(batchReader, insideChangeset);
                            if (!insideChangeset)
                            {
                                #region Get response
                                Debug.Assert(operationCount == 0, "missing an EndChangeSet 2");

                                QueryOperationResponse qresponse = null;
                                try
                                {
                                    if (exception == null)
                                    {
                                        DataServiceRequest query = this.Queries[queryCount];
                                        ResponseInfo responseInfo = this.RequestInfo.GetDeserializationInfo(null /*mergeOption*/);
                                        MaterializeAtom materializer = DataServiceRequest.Materialize(
                                            responseInfo,
                                            query.QueryComponents(this.RequestInfo.Model),
                                            null,
                                            this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType),
                                            this.currentOperationResponse.CreateResponseMessage(),
                                            query.PayloadKind);
                                        qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer);
                                    }
                                }
                                catch (ArgumentException e)
                                {
                                    exception = e;
                                }
                                catch (FormatException e)
                                {
                                    exception = e;
                                }
                                catch (InvalidOperationException e)
                                {
                                    exception = e;
                                }

                                if (qresponse == null)
                                {
                                    if (this.Queries != null)
                                    {
                                        // this is the normal ExecuteBatch response
                                        DataServiceRequest query = this.Queries[queryCount];

                                        if (this.RequestInfo.IgnoreResourceNotFoundException && this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound)
                                        {
                                            qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                        }
                                        else
                                        {
                                            qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults);
                                            qresponse.Error = exception;
                                        }
                                    }
                                    else
                                    {
                                        // This is top-level failure for SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) or SaveChanges(SaveChangesOptions.BatchWithIndependentOperations) operations.
                                        // example: server doesn't support batching or number of batch objects exceeded an allowed limit.
                                        // ex could be null if the server responded to SaveChanges with an unexpected success with
                                        // response of batched GETS that did not correspond the original POST/PATCH/PUT/DELETE requests.
                                        // we expect non-null since server should have failed with a non-success code
                                        // and HandleResponse(status, ...) should generate the exception object
                                        throw exception;
                                    }
                                }

                                qresponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                                queryCount++;
                                yield return qresponse;
                                #endregion
                            }
                            else
                            {
                                #region Update response
                                try
                                {
                                    Descriptor descriptor = this.ChangedEntries[this.entryIndex];
                                    operationCount += this.SaveResultProcessed(descriptor);

                                    if (exception != null)
                                    {
                                        throw exception;
                                    }

                                    this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers);
#if DEBUG
                                    this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers, this.currentOperationResponse.StatusCode);
#else
                                    this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers);
#endif
                                }
                                catch (Exception e)
                                {
                                    this.ChangedEntries[this.entryIndex].SaveError = e;
                                    exception = e;

                                    if (!CommonUtil.IsCatchableExceptionType(e))
                                    {
                                        throw;
                                    }
                                }

                                ChangeOperationResponse changeOperationResponse =
                                    new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]);
                                changeOperationResponse.StatusCode = (int)this.currentOperationResponse.StatusCode;
                                if (exception != null)
                                {
                                    changeOperationResponse.Error = exception;
                                }

                                operationCount++;
                                this.entryIndex++;
                                yield return changeOperationResponse;
                                #endregion
                            }

                            break;
                        #endregion

                        default:
                            Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState);
                            break;
                    }
                }

                Debug.Assert(batchReader.State == ODataBatchReaderState.Completed, "unexpected batch state");

                // Check for a changeset without response (first line) or GET request without response (second line).
                // either all saved entries must be processed or it was a batch and one of the entries has the error
                if ((this.Queries == null &&
                    (!changesetFound ||
                     0 < queryCount ||
                     this.ChangedEntries.Any(o => o.ContentGeneratedForSave && o.SaveResultWasProcessed == 0) &&
                     (!this.IsBatchRequest || this.ChangedEntries.FirstOrDefault(o => o.SaveError != null) == null))) ||
                    (this.Queries != null && queryCount != this.Queries.Length))
                {
                    throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount);
                }
            }
            finally
            {
                // Note that this will be called only once the enumeration of all responses is finished and the Dispose
                // was called on the IEnumerator used for that enumeration. It is not called when the method returns,
                // since the compiler change this method to return the compiler-generated IEnumerable.
                Util.Dispose(ref this.batchMessageReader);
            }
        }