예제 #1
0
            public ODataResource CreateEntry(ODataBatchOperationRequestMessage batchRequest, out IEdmEntitySet entitSet)
            {
                if (batchRequest.Method == ODataConstants.MethodDelete)
                {
                    return(ReadEntityFromUrl(batchRequest.Url, out entitSet));
                }

                String contentType = batchRequest.GetHeader(ODataConstants.ContentTypeHeader);

                using (Stream stream = batchRequest.GetStream())
                    return(ReadEntityFromStream(stream, batchRequest.Url, contentType, out entitSet));
            }
예제 #2
0
        private static async Task <HttpContext> ReadOperationInternalAsync(
            ODataBatchReader reader, HttpContext originalContext, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true)
        {
            ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync();

            HttpContext context = CreateHttpContext(originalContext);
            HttpRequest request = context.Request;

            request.Method = batchRequest.Method;
            request.CopyAbsoluteUrl(batchRequest.Url);

            // Not using bufferContentStream. Unlike AspNet, AspNetCore cannot guarantee the disposal
            // of the stream in the context of execution so there is no choice but to copy the stream
            // from the batch reader.
            using (Stream stream = batchRequest.GetStream())
            {
                MemoryStream bufferedStream = new MemoryStream();
                // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token
                await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken);

                bufferedStream.Position = 0;
                request.Body            = bufferedStream;
            }

            foreach (var header in batchRequest.Headers)
            {
                string headerName  = header.Key;
                string headerValue = header.Value;

                if (headerName.Trim().ToLowerInvariant() == "prefer")
                {
                    // in the case of Prefer header, we don't want to overwrite,
                    // instead we merge preferences defined in the individual request with those inherited from the batch
                    request.Headers.TryGetValue(headerName, out StringValues batchReferences);
                    request.Headers[headerName] = MergeIndividualAndBatchPreferences(headerValue, batchReferences);
                }
                else
                {
                    // Copy headers from batch, overwriting any existing headers.
                    request.Headers[headerName] = headerValue;
                }
            }

            request.SetODataBatchId(batchId);
            request.SetODataContentId(batchRequest.ContentId);

            if (changeSetId != null && changeSetId.HasValue)
            {
                request.SetODataChangeSetId(changeSetId.Value);
            }

            return(context);
        }
예제 #3
0
        private static BatchWriterStatesTestSetupResult GetOperationStream(object message, WriterTestConfiguration testConfiguration)
        {
            BatchWriterStatesTestSetupResult result = new BatchWriterStatesTestSetupResult {
                Message = message
            };

            ODataBatchOperationRequestMessage requestMessage = message as ODataBatchOperationRequestMessage;

            if (requestMessage != null)
            {
                if (testConfiguration.Synchronous)
                {
                    result.MessageStream = requestMessage.GetStream();
                    return(result);
                }
                else
                {
                    // TODO: 191417: Enable async Tests on Phone and Silverlight when Product Supports them
#if SILVERLIGHT || WINDOWS_PHONE
                    throw new TaupoNotSupportedException("This test is not supported in aSynchronous mode in Silverlight or Phone");
#else
                    var t = requestMessage.GetStreamAsync();
                    t.Wait();
                    result.MessageStream = t.Result;
                    return(result);
#endif
                }
            }

            ODataBatchOperationResponseMessage responseMessage = message as ODataBatchOperationResponseMessage;
            if (responseMessage != null)
            {
                if (testConfiguration.Synchronous)
                {
                    result.MessageStream = responseMessage.GetStream();
                    return(result);
                }
                else
                {
                    // TODO: Enable async Tests on Phone and Silverlight when Product Supports them
#if SILVERLIGHT || WINDOWS_PHONE
                    throw new TaupoNotSupportedException("This test is not supported in aSynchronous mode in Silverlight or Phone");
#else
                    var t = responseMessage.GetStreamAsync();
                    t.Wait();
                    result.MessageStream = t.Result;
                    return(result);
#endif
                }
            }

            return(null);
        }
 private static Stream GetMessageStream(ODataBatchOperationRequestMessage requestMessage, WriterTestConfiguration testConfiguration)
 {
     if (testConfiguration.Synchronous)
     {
         return(requestMessage.GetStream());
     }
     else
     {
         var t = requestMessage.GetStreamAsync();
         t.Wait();
         return(t.Result);
     }
 }
예제 #5
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            string requestLine = this.batchStream.ReadFirstNonEmptyLine();

            string httpMethod;
            Uri    requestUri;

            this.ParseRequestLine(requestLine, out httpMethod, out requestUri);

            // Read all headers and create the request message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.batchStream.ChangeSetBoundary != null)
            {
                if (this.currentContentId == null)
                {
                    headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId);

                    if (this.currentContentId == null)
                    {
                        throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader));
                    }
                }
            }
            else if (this.InputContext.MessageReaderSettings.Version <= ODataVersion.V4)
            {
                // For backward compatibility, don't enforce uniqueness of Content-ID
                // in MultipartMixed outside of a changeset
                this.PayloadUriConverter.Reset();
            }

            ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                httpMethod,
                requestUri,
                headers,
                this.currentContentId,
                this.batchStream.ChangeSetBoundary,
                this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false);

            if (this.currentContentId != null)
            {
                this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId);
            }

            this.currentContentId = null;

            return(requestMessage);
        }
예제 #6
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        private ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            this.operationState = OperationState.MessageCreated;

            string requestLine = this.batchStream.ReadFirstNonEmptyLine();

            string httpMethod;
            Uri    requestUri;

            this.ParseRequestLine(requestLine, out httpMethod, out requestUri);

            // Read all headers and create the request message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.batchStream.ChangeSetBoundary != null)
            {
                if (this.allowLegacyContentIdBehaviour)
                {
                    // Add a potential Content-ID header to the URL resolver so that it will be available
                    // to subsequent operations.
                    string contentId;
                    if (this.contentIdToAddOnNextRead == null && headers.TryGetValue(ODataConstants.ContentIdHeader, out contentId))
                    {
                        if (contentId != null && this.urlResolver.ContainsContentId(contentId))
                        {
                            throw new ODataException(Strings.ODataBatchReader_DuplicateContentIDsNotAllowed(contentId));
                        }

                        this.contentIdToAddOnNextRead = contentId;
                    }
                }

                if (this.contentIdToAddOnNextRead == null)
                {
                    throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader));
                }
            }

            ODataBatchOperationRequestMessage requestMessage = ODataBatchOperationRequestMessage.CreateReadMessage(
                this.batchStream,
                httpMethod,
                requestUri,
                headers,
                /*operationListener*/ this,
                this.contentIdToAddOnNextRead,
                this.urlResolver);

            return(requestMessage);
        }
        private byte[] ClientWriteBatchRequest(BodyContentType bodyContentType)
        {
            MemoryStream stream = new MemoryStream();

            IODataRequestMessage requestMessage = new InMemoryMessage {
                Stream = stream
            };

            requestMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson);

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

                batchWriter.WriteStartBatch();

                // Write a change set with update operation.
                batchWriter.WriteStartChangeset();

                // Create an update operation in the change set.
                ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage(
                    "PUT", new Uri(serviceDocumentUri + "MyBlob"), "1");

                // Set the content type with explicit character set so that the content string
                // is flushed into the operation message body stream without byte-order-mark.
                updateOperationMessage.SetHeader("CoNtEnt-TYPE", GetContentType(bodyContentType));

                // Use the message writer to write encoded string content.
                using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                {
                    operationMessageWriter.WriteValue(GetEncodedContentObject(bodyContentType, /*forRequest*/ true));
                }

                batchWriter.WriteEndChangeset();

                // Write a query operation.
                ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage(
                    "GET", new Uri(serviceDocumentUri + "MyBlob"), /*contentId*/ null);

                // Header modification on inner payload.
                queryOperationMessage.SetHeader("AcCePt", GetContentType(bodyContentType));

                batchWriter.WriteEndBatch();

                stream.Position = 0;
                return(stream.ToArray());
            }
        }
예제 #8
0
        public static OeOperationMessage Create(OeMessageContext context, ODataBatchReader reader)
        {
            ODataBatchOperationRequestMessage batchRequest = reader.CreateOperationRequestMessage();
            var operation = new OeOperationMessage(batchRequest);

            if (batchRequest.Method == ODataConstants.MethodDelete)
            {
                operation.EntityItem = operation.ReadEntityFromUrl(context);
            }
            else
            {
                using (Stream stream = batchRequest.GetStream())
                    operation.EntityItem = operation.ReadEntityFromStream(context, stream);
            }
            return(operation);
        }
예제 #9
0
        private static async Task <HttpRequestMessage> ReadOperationInternalAsync(
            ODataBatchReader reader, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true)
        {
            ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync();

            HttpRequestMessage request = new HttpRequestMessage();

            request.Method     = new HttpMethod(batchRequest.Method);
            request.RequestUri = batchRequest.Url;

            if (bufferContentStream)
            {
                using (Stream stream = await batchRequest.GetStreamAsync())
                {
                    MemoryStream bufferedStream = new MemoryStream();
                    // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token
                    await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken);

                    bufferedStream.Position = 0;
                    request.Content         = new StreamContent(bufferedStream);
                }
            }
            else
            {
                request.Content = new LazyStreamContent(() => batchRequest.GetStreamAsync().Result);
            }

            foreach (var header in batchRequest.Headers)
            {
                string headerName  = header.Key;
                string headerValue = header.Value;
                if (!request.Headers.TryAddWithoutValidation(headerName, headerValue))
                {
                    request.Content.Headers.TryAddWithoutValidation(headerName, headerValue);
                }
            }

            request.SetODataBatchId(batchId);
            request.SetODataContentId(batchRequest.ContentId);

            if (changeSetId != null && changeSetId.HasValue)
            {
                request.SetODataChangeSetId(changeSetId.Value);
            }

            return(request);
        }
 private static void SetAcceptAndContentTypeForODataBatchMessage(ODataBatchOperationRequestMessage mimePartMsg, TablePayloadFormat payloadFormat)
 {
     if (payloadFormat == TablePayloadFormat.JsonFullMetadata)
     {
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonFullMetadataAcceptHeaderValue);
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue);
     }
     else if (payloadFormat == TablePayloadFormat.Json)
     {
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonLightAcceptHeaderValue);
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue);
     }
     else
     {
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonNoMetadataAcceptHeaderValue);
         mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue);
     }
 }
예제 #11
0
        private static BatchWriterStatesTestSetupResult GetOperationStream(object message, WriterTestConfiguration testConfiguration)
        {
            BatchWriterStatesTestSetupResult result = new BatchWriterStatesTestSetupResult {
                Message = message
            };

            ODataBatchOperationRequestMessage requestMessage = message as ODataBatchOperationRequestMessage;

            if (requestMessage != null)
            {
                if (testConfiguration.Synchronous)
                {
                    result.MessageStream = requestMessage.GetStream();
                    return(result);
                }
                else
                {
                    var t = requestMessage.GetStreamAsync();
                    t.Wait();
                    result.MessageStream = t.Result;
                    return(result);
                }
            }

            ODataBatchOperationResponseMessage responseMessage = message as ODataBatchOperationResponseMessage;

            if (responseMessage != null)
            {
                if (testConfiguration.Synchronous)
                {
                    result.MessageStream = responseMessage.GetStream();
                    return(result);
                }
                else
                {
                    var t = responseMessage.GetStreamAsync();
                    t.Wait();
                    result.MessageStream = t.Result;
                    return(result);
                }
            }

            return(null);
        }
예제 #12
0
        private static async Task <HttpRequestMessage> ReadOperationInternalAsync(ODataBatchReader reader, Guid batchId, Guid?changeSetId, bool bufferContentStream = true)
        {
            ODataBatchOperationRequestMessage batchRequest = reader.CreateOperationRequestMessage();
            HttpRequestMessage request = new HttpRequestMessage();

            request.Method     = new HttpMethod(batchRequest.Method);
            request.RequestUri = batchRequest.Url;

            if (bufferContentStream)
            {
                using (Stream stream = batchRequest.GetStream())
                {
                    MemoryStream bufferedStream = new MemoryStream();
                    await stream.CopyToAsync(bufferedStream);

                    bufferedStream.Position = 0;
                    request.Content         = new StreamContent(bufferedStream);
                }
            }
            else
            {
                request.Content = new LazyStreamContent(() => batchRequest.GetStream());
            }

            foreach (var header in batchRequest.Headers)
            {
                string headerName  = header.Key;
                string headerValue = header.Value;
                if (!request.Headers.TryAddWithoutValidation(headerName, headerValue))
                {
                    request.Content.Headers.TryAddWithoutValidation(headerName, headerValue);
                }
            }

            request.SetODataBatchId(batchId);

            if (changeSetId != null && changeSetId.HasValue)
            {
                request.SetODataChangeSetId(changeSetId.Value);
            }

            return(request);
        }
예제 #13
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            string requestLine = this.batchStream.ReadFirstNonEmptyLine();

            string httpMethod;
            Uri    requestUri;

            this.ParseRequestLine(requestLine, out httpMethod, out requestUri);

            // Read all headers and create the request message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.batchStream.ChangeSetBoundary != null)
            {
                if (this.currentContentId == null)
                {
                    headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId);

                    if (this.currentContentId == null)
                    {
                        throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader));
                    }
                }
            }

            ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                httpMethod,
                requestUri,
                headers,
                this.currentContentId,
                this.batchStream.ChangeSetBoundary,
                this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false);

            if (this.currentContentId != null)
            {
                this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId);
            }

            this.currentContentId = null;

            return(requestMessage);
        }
예제 #14
0
        private static async Task <HttpContext> ReadOperationInternalAsync(
            ODataBatchReader reader, HttpContext originalContext, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true)
        {
            ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync();

            HttpContext context = CreateHttpContext(originalContext);
            HttpRequest request = context.Request;

            request.Method = batchRequest.Method;
            request.CopyAbsoluteUrl(batchRequest.Url);

            // Not using bufferContentStream. Unlike AspNet, AspNetCore cannot guarantee the disposal
            // of the stream in the context of execution so there is no choice but to copy the stream
            // from the batch reader.
            using (Stream stream = batchRequest.GetStream())
            {
                MemoryStream bufferedStream = new MemoryStream();
                // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token
                await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken);

                bufferedStream.Position = 0;
                request.Body            = bufferedStream;
            }

            foreach (var header in batchRequest.Headers)
            {
                // Copy headers from batch, overwriting any existing headers.
                string headerName  = header.Key;
                string headerValue = header.Value;
                request.Headers[headerName] = headerValue;
            }

            request.SetODataBatchId(batchId);
            request.SetODataContentId(batchRequest.ContentId);

            if (changeSetId != null && changeSetId.HasValue)
            {
                request.SetODataChangeSetId(changeSetId.Value);
            }

            return(context);
        }
        /// <summary>
        /// Asynchronously creates an <see cref="ODataBatchOperationRequestMessage"/> for writing an operation of a batch request
        /// - implementation of the actual functionality.
        /// </summary>
        /// <param name="method">The Http method to be used for this request operation.</param>
        /// <param name="uri">The Uri to be used for this request operation.</param>
        /// <param name="contentId">The Content-ID value to write in ChangeSet head.</param>
        /// <param name="payloadUriOption">
        /// The format of operation Request-URI, which could be AbsoluteUri, AbsoluteResourcePathAndHost, or RelativeResourcePath.</param>
        /// <param name="dependsOnIds">The prerequisite request ids of this request. By default its value should be null for Multipart/Mixed
        /// format and the dependsOnIds implicitly derived per the protocol will be used; Otherwise, non-null will be used as override after
        /// validation.</param>
        /// <returns>A task that represents the asynchronous operation.
        /// The value of the TResult parameter contains an <see cref="ODataBatchOperationRequestMessage"/>
        /// that can be used to write the request operation.</returns>
        protected override async Task <ODataBatchOperationRequestMessage> CreateOperationRequestMessageImplementationAsync(
            string method, Uri uri, string contentId, BatchPayloadUriOption payloadUriOption,
            IEnumerable <string> dependsOnIds)
        {
            // Write pending message data (headers, response line) for a previously unclosed message/request
            await this.WritePendingMessageDataAsync(true)
            .ConfigureAwait(false);

            // Create the new request operation
            // For Multipart batch format, validate dependsOnIds if it is user explicit input, otherwise skip validation
            // when it is implicitly derived per protocol.
            ODataBatchOperationRequestMessage operationRequestMessage = BuildOperationRequestMessage(
                this.RawOutputContext.OutputStream,
                method, uri, contentId,
                this.changeSetBoundary,
                dependsOnIds);

            this.SetState(BatchWriterState.OperationCreated);

            // Write the operation's start boundary string
            await this.WriteStartBoundaryForOperationAsync()
            .ConfigureAwait(false);

            if (contentId != null)
            {
                this.dependsOnIdsTracker.AddDependsOnId(contentId);
            }

            // Write the headers and request line
            await ODataMultipartMixedBatchWriterUtils.WriteRequestPreambleAsync(
                this.RawOutputContext.TextWriter,
                method,
                uri,
                this.RawOutputContext.MessageWriterSettings.BaseUri,
                changeSetBoundary != null,
                contentId,
                payloadUriOption).ConfigureAwait(false);

            return(operationRequestMessage);
        }
        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;
                    }
                }
            }
        }
        /// <summary>
        /// Creates an <see cref="ODataBatchOperationRequestMessage"/> for writing an operation of a batch request
        /// - implementation of the actual functionality.
        /// </summary>
        /// <param name="method">The Http method to be used for this request operation.</param>
        /// <param name="uri">The Uri to be used for this request operation.</param>
        /// <param name="contentId">The Content-ID value to write in ChangeSet head.</param>
        /// <param name="payloadUriOption">
        /// The format of operation Request-URI, which could be AbsoluteUri, AbsoluteResourcePathAndHost, or RelativeResourcePath.</param>
        /// <param name="dependsOnIds">The prerequisite request ids of this request.</param>
        /// <returns>The message that can be used to write the request operation.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation(
            string method, Uri uri, string contentId, BatchPayloadUriOption payloadUriOption,
            IEnumerable<string> dependsOnIds)
        {
            // write pending message data (headers, response line) for a previously unclosed message/request
            this.WritePendingMessageData(true);

            // create the new request operation
            ODataBatchOperationRequestMessage operationRequestMessage = BuildOperationRequestMessage(
                this.RawOutputContext.OutputStream,
                method, uri, contentId, /*groupId*/null, dependsOnIds, ODataFormat.Batch);

            this.SetState(BatchWriterState.OperationCreated);

            // write the operation's start boundary string
            this.WriteStartBoundaryForOperation();

            // write the headers and request line
            ODataMultipartMixedBatchWriterUtils.WriteRequestPreamble(this.RawOutputContext.TextWriter, method, uri,
                this.RawOutputContext.MessageWriterSettings.BaseUri, changeSetBoundary != null, contentId,
                payloadUriOption);

            return operationRequestMessage;
        }
 private static Stream GetMessageStream(ODataBatchOperationRequestMessage requestMessage, WriterTestConfiguration testConfiguration)
 {
     if (testConfiguration.Synchronous)
     {
         return requestMessage.GetStream();
     }
     else
     {
         var t = requestMessage.GetStreamAsync();
         t.Wait();
         return t.Result;
     }
 }
        internal static StorageRequestMessage BuildRequestForTableBatchOperation <T>(RESTCommand <T> cmd, Uri uri, UriQueryBuilder builder, int?timeout, string tableName, TableBatchOperation batch, CloudTableClient client, HttpContent content, OperationContext ctx, TablePayloadFormat payloadFormat, ICanonicalizer canonicalizer, StorageCredentials credentials)
        {
            StorageRequestMessage msg = BuildRequestCore(NavigationHelper.AppendPathToSingleUri(uri, "$batch"), builder, HttpMethod.Post, timeout, content, ctx, canonicalizer, credentials);

            Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat);

            // create the writer, indent for readability of the examples.
            ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
            {
                CheckCharacters = false,                              // sets this flag on the XmlWriter for ATOM
                Version         = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry
            };

            HttpRequestAdapterMessage adapterMsg = new HttpRequestAdapterMessage(msg, client.BufferManager, 64 * (int)Constants.KB);

            cmd.StreamToDispose = adapterMsg.GetStream();

            // Start Batch
            ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings);
            ODataBatchWriter   batchWriter = odataWriter.CreateODataBatchWriter();

            batchWriter.WriteStartBatch();

            bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve;

            // Query operations should not be inside changeset in payload
            if (!isQuery)
            {
                // Start Operation
                batchWriter.WriteStartChangeset();
                batchWriter.Flush();
            }

            foreach (TableOperation operation in batch)
            {
                string httpMethod = operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge ? "MERGE" : operation.HttpMethod.Method;

                ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(uri, tableName));
                SetAcceptAndContentTypeForODataBatchMessage(mimePartMsg, payloadFormat);

                // etag
                if (operation.OperationType == TableOperationType.Delete ||
                    operation.OperationType == TableOperationType.Replace ||
                    operation.OperationType == TableOperationType.Merge)
                {
                    mimePartMsg.SetHeader("If-Match", operation.Entity.ETag);
                }

                // Prefer header
                if (operation.OperationType == TableOperationType.Insert)
                {
                    mimePartMsg.SetHeader("Prefer", operation.EchoContent ? "return-content" : "return-no-content");
                }

                if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve)
                {
                    using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings, new TableStorageModel(client.AccountName)))
                    {
                        // Write entity
                        ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter();
                        WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter);
                    }
                }
            }

            if (!isQuery)
            {
                // End Operation
                batchWriter.WriteEndChangeset();
            }

            // End Batch
            batchWriter.WriteEndBatch();
            batchWriter.Flush();

            return(adapterMsg.GetPopulatedMessage());
        }
예제 #20
0
        private byte[] CreateBatchRequest(string batchContentType, int unitRepeatCount)
        {
            Debug.Assert(!string.IsNullOrEmpty(batchContentType), "!string.IsNullOrEmpty(batchContentType)");

            MemoryStream stream = new MemoryStream();

            IODataRequestMessage requestMessage = new InMemoryMessage {
                Stream = stream
            };

            requestMessage.SetHeader("Content-Type", batchContentType);
            ODataMessageWriterSettings settings = new ODataMessageWriterSettings();

            settings.BaseUri = new Uri(serviceDocumentUri);

            using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings))
            {
                ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                // Each iteration generates a change set with two operations, followed by one top level operation.
                // Operations count in each iteration is three.
                // Use API available in OData 7.2
                for (int idx = 0; idx < unitRepeatCount * NumOfRequestPerUnit; idx += NumOfRequestPerUnit)
                {
                    batchWriter.WriteStartChangeset();

                    ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "PUT",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        idx.ToString());

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage))
                    {
                        ODataWriter   entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        ODataResource entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[]
                            {
                                new ODataProperty()
                                {
                                    Name = "WebId", Value = "webid_" + idx
                                },
                                new ODataProperty()
                                {
                                    Name = "Name", Value = this.aLongString
                                }
                            }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    // A PATCH operation.
                    ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "PATCH",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        (idx + 1).ToString(),
                        BatchPayloadUriOption.AbsoluteUri);

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                    {
                        var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        var entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[] { new ODataProperty()
                                                 {
                                                     Name = "WebId", Value = "webid_" + (idx + 1)
                                                 } }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    batchWriter.WriteEndChangeset();

                    ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "GET",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        (idx + 2).ToString());
                    queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full");
                }

                batchWriter.WriteEndBatch();

                stream.Position = 0;
                return(stream.ToArray());
            }
        }
예제 #21
0
        private byte[] CreateBigBatchRequest(int repeatCount)
        {
            MemoryStream stream = new MemoryStream();

            IODataRequestMessage requestMessage = new InMemoryMessage {
                Stream = stream
            };

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

            settings.BaseUri = new Uri(serviceDocumentUri);

            using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings))
            {
                ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                // Each iteration generates a change set with two operations, followed by one top level operation.
                // Operations count in each iteration is three.
                for (int idx = 0; idx < repeatCount * 3; idx += 3)
                {
                    batchWriter.WriteStartChangeset();

                    ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "PUT",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        idx.ToString());

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage))
                    {
                        ODataWriter   entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        ODataResource entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[]
                            {
                                new ODataProperty()
                                {
                                    Name = "WebId", Value = "webid_" + idx
                                },
                                new ODataProperty()
                                {
                                    Name = "Name", Value = this.aVeryLongString
                                }
                            }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    // A PATCH operation that depends on the preceding PUT operation.
                    List <string> dependsOnIds = new List <string> {
                        idx.ToString()
                    };

                    ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "PATCH",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$" + idx)),
                        (idx + 1).ToString(),
                        BatchPayloadUriOption.AbsoluteUri,
                        dependsOnIds);

                    // Verify that input values are copied into a new list.
                    Assert.Equal(dependsOnIds, updateOperationMessage.DependsOnIds);
                    Assert.NotSame(dependsOnIds, updateOperationMessage.DependsOnIds);

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                    {
                        var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        var entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[] { new ODataProperty()
                                                 {
                                                     Name = "WebId", Value = "webid_" + (idx + 1)
                                                 } }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId);
                    batchWriter.WriteEndChangeset();

                    ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage(
                        "GET",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        (idx + 2).ToString());
                    queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full");
                }

                batchWriter.WriteEndBatch();

                stream.Position = 0;
                return(stream.ToArray());
            }
        }
예제 #22
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);
            }
        }
예제 #23
0
        internal static HttpRequestMessage BuildRequestForTableBatchOperation(Uri uri, int?timeout, Uri baseUri, string tableName, TableBatchOperation batch, OperationContext ctx)
        {
            HttpRequestMessage msg = BuildRequestCore(NavigationHelper.AppendPathToUri(uri, "$batch"), HttpMethod.Post, timeout, ctx);

            // create the writer, indent for readability of the examples.
            ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
            {
                CheckCharacters = false,          // sets this flag on the XmlWriter for ATOM
                Version         = ODataVersion.V2 // set the Odata version to use when writing the entry
            };

            HttpRequestAdapterMessage adapterMsg = new HttpRequestAdapterMessage(msg);

            // Start Batch
            ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings);
            ODataBatchWriter   batchWriter = odataWriter.CreateODataBatchWriter();

            batchWriter.WriteStartBatch();

            bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve;

            // Query operations should not be inside changeset in payload
            if (!isQuery)
            {
                // Start Operation
                batchWriter.WriteStartChangeset();
                batchWriter.Flush();
            }

            foreach (TableOperation operation in batch)
            {
                string httpMethod = operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge ? "MERGE" : operation.HttpMethod.Method;

                ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(baseUri, tableName));

                // etag
                if (operation.OperationType == TableOperationType.Delete ||
                    operation.OperationType == TableOperationType.Replace ||
                    operation.OperationType == TableOperationType.Merge)
                {
                    mimePartMsg.SetHeader("If-Match", operation.Entity.ETag);
                }

                if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve)
                {
                    using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings))
                    {
                        // Write entity
                        ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter();
                        WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter);
                    }
                }
            }

            if (!isQuery)
            {
                // End Operation
                batchWriter.WriteEndChangeset();
            }

            // End Batch
            batchWriter.WriteEndBatch();
            batchWriter.Flush();

            return(adapterMsg.GetPopulatedMessage());
        }
        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());
            }
        }
예제 #25
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);
            }
        }
예제 #26
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            Debug.Assert(this.mode == ReaderMode.Requests, "this.mode == ReaderMode.Requests");
            Debug.Assert(this.messagePropertiesCache != null, "this.messagePropertiesCache != null");

            // id
            string id = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameId);

            // atomicityGroup
            string atomicityGroupId = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameAtomicityGroup);

            if (id != null)
            {
                this.requestIds.Add(id);
            }

            if (atomicityGroupId != null)
            {
                this.requestIds.Add(atomicityGroupId);
            }

            // dependsOn
            // Flatten the dependsOn list by converting every groupId into request Ids, so that the caller
            // can decide, at the earliest opportunity, whether the depending request can be invoked.
            // Note that the forward reference of dependsOn id is not allowed, so the atomicGroups should have accurate
            // information of atomicGroup that needs to be flattened.
            IList <string> dependsOnReqIds = null;
            List <string>  dependsOn       = (List <string>) this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameDependsOn);

            if (dependsOn != null && dependsOn.Count != 0)
            {
                ValidateDependsOnId(dependsOn, atomicityGroupId, id);
                dependsOnReqIds = atomicGroups.GetFlattenedMessageIds(dependsOn);
            }

            // header
            ODataBatchOperationHeaders headers =
                (ODataBatchOperationHeaders)this.messagePropertiesCache.GetPropertyValue(
                    ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameHeaders);

            // Add the atomicityGroup request header.
            if (atomicityGroupId != null)
            {
                headers.Add(ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameAtomicityGroup, atomicityGroupId);
            }

            // body. Use empty stream when request body is not present.
            Stream bodyContentStream =
                (Stream)this.messagePropertiesCache.GetPropertyValue(
                    ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameBody)
                ?? new ODataJsonLightBatchBodyContentReaderStream(this);

            // method. Support case-insensitive value of HTTP methods.
            string httpMethod = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameMethod);

            ValidateRequiredProperty(httpMethod, ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameMethod);

            httpMethod = httpMethod.ToUpperInvariant();

            // url
            string url = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameUrl);

            ValidateRequiredProperty(url, ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameUrl);

            // escape any colons in the query string portion of the url
            int queryOptionSeparator = url.IndexOf('?');
            int firstColon           = url.IndexOf(':');

            if (queryOptionSeparator > 0 && firstColon > 0 && queryOptionSeparator < firstColon)
            {
                url = url.Substring(0, queryOptionSeparator) + url.Substring(queryOptionSeparator).Replace(":", "%3A");
            }

            Uri requestUri = new Uri(url, UriKind.RelativeOrAbsolute);

            // Reset the request property cache since all data in cache has been processed.
            // So that new instance can be created during subsequent read in operation state.
            this.messagePropertiesCache = null;

            ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage(
                () => bodyContentStream,
                httpMethod,
                requestUri,
                headers,
                id,
                atomicityGroupId,
                dependsOnReqIds,
                /*dependsOnIdsValidationRequired*/ true);

            return(requestMessage);
        }
예제 #27
0
        /// <summary>
        /// Create a batch request that contains one atomic groups.
        /// </summary>
        /// <param name="atomicGroupIdFromRequest">Output string for the atomic group id from the batch created.</param>
        /// <returns>Stream containing the batch request.</returns>
        private byte[] CreateBatchRequestWithAtomicGroup(out string atomicGroupIdFromRequest)
        {
            MemoryStream stream = new MemoryStream();

            IODataRequestMessage requestMessage = new InMemoryMessage {
                Stream = stream
            };

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

            settings.BaseUri = new Uri(serviceDocumentUri);

            using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings))
            {
                ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                batchWriter.WriteStartChangeset();

                // Create operation.
                ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage(
                    "PUT",
                    new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                    "1");

                using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage))
                {
                    ODataWriter   entryWriter = operationMessageWriter.CreateODataResourceWriter();
                    ODataResource entry       = new ODataResource()
                    {
                        TypeName   = "NS.Web",
                        Properties = new[]
                        {
                            new ODataProperty()
                            {
                                Name = "WebId", Value = 10
                            },
                            new ODataProperty()
                            {
                                Name = "Name", Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest"
                            }
                        }
                    };
                    entryWriter.WriteStart(entry);
                    entryWriter.WriteEnd();
                }

                // A PATCH operation that depends on the preceding PUT operation.
                List <string> dependsOnIds = new List <string> {
                    "1"
                };

                ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage(
                    "PATCH",
                    new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1")),
                    "2",
                    BatchPayloadUriOption.AbsoluteUri,
                    dependsOnIds);

                // Verify that input values are copied into a new list.
                Assert.Equal(dependsOnIds, updateOperationMessage.DependsOnIds);
                Assert.NotSame(dependsOnIds, updateOperationMessage.DependsOnIds);

                using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                {
                    var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                    var entry       = new ODataResource()
                    {
                        TypeName   = "NS.Web",
                        Properties = new[] { new ODataProperty()
                                             {
                                                 Name = "WebId", Value = 11
                                             } }
                    };
                    entryWriter.WriteStart(entry);
                    entryWriter.WriteEnd();
                }

                Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId);
                batchWriter.WriteEndChangeset();

                ODataBatchOperationRequestMessage update2OperationMessage = batchWriter.CreateOperationRequestMessage(
                    "PATCH",
                    new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                    "3",
                    BatchPayloadUriOption.AbsoluteUri);

                using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(update2OperationMessage))
                {
                    var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                    var entry       = new ODataResource()
                    {
                        TypeName   = "NS.Web",
                        Properties = new[] { new ODataProperty()
                                             {
                                                 Name = "WebId", Value = 12
                                             } }
                    };
                    entryWriter.WriteStart(entry);
                    entryWriter.WriteEnd();
                }
                batchWriter.WriteEndBatch();
                atomicGroupIdFromRequest = createOperationMessage.GroupId;

                stream.Position = 0;
                return(stream.ToArray());
            }
        }
예제 #28
0
        private void BatchRequestWithPayloadUriWritingOption(BatchPayloadUriOption option)
        {
            var writerSettings = new ODataMessageWriterSettings();

            writerSettings.BaseUri = ServiceBaseUri;
            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings()
            {
                BaseUri = ServiceBaseUri
            };

            var accountType                = Model.FindDeclaredType(NameSpacePrefix + "Account") as IEdmEntityType;
            var accountSet                 = Model.EntityContainer.FindEntitySet("Accounts");
            var paymentInstrumentType      = Model.FindDeclaredType(NameSpacePrefix + "PaymentInstrument") as IEdmEntityType;
            IEdmNavigationProperty navProp = accountType.FindProperty("MyPaymentInstruments") as IEdmNavigationProperty;
            var myPaymentInstrumentSet     = accountSet.FindNavigationTarget(navProp);

            var requestMessage = new HttpWebRequestMessage(new Uri(ServiceBaseUri + "$batch"));

            requestMessage.SetHeader("Content-Type", "multipart/mixed;boundary=batch_01AD6766-4A45-47CC-9463-94D4591D8DA9");
            requestMessage.SetHeader("OData-Version", "4.0");
            requestMessage.Method = "POST";

            using (var messageWriter = new ODataMessageWriter(requestMessage, writerSettings, Model))
            {
                var batchWriter = messageWriter.CreateODataBatchWriter();

                //Batch start.
                batchWriter.WriteStartBatch();

                //A Get request.

                var batchOperation1 = batchWriter.CreateOperationRequestMessage("GET", new Uri(ServiceBaseUri + "Accounts(101)/MyPaymentInstruments"), null, option);
                batchOperation1.SetHeader("Accept", "application/json;odata.metadata=full");
                //Get request ends.

                //Changeset start.
                batchWriter.WriteStartChangeset();

                //The first operation in changeset is a Create request.

                ODataBatchOperationRequestMessage batchChangesetOperation1 = batchWriter.CreateOperationRequestMessage("POST", new Uri(ServiceBaseUri + "Accounts(102)/MyPaymentInstruments"), "1", option);
                batchChangesetOperation1.SetHeader("Content-Type", "application/json;odata.metadata=full");
                batchChangesetOperation1.SetHeader("Accept", "application/json;odata.metadata=full");
                var paymentInstrumentEntry = new ODataResource()
                {
                    TypeName = NameSpacePrefix + "PaymentInstrument"
                };
                var paymentInstrumentEntryP1 = new ODataProperty {
                    Name = "PaymentInstrumentID", Value = 102910
                };
                var paymentInstrumentEntryP2 = new ODataProperty {
                    Name = "FriendlyName", Value = "102 batch new PI"
                };
                var paymentInstrumentEntryP3 = new ODataProperty {
                    Name = "CreatedDate", Value = new DateTimeOffset(new DateTime(2013, 12, 29, 11, 11, 57))
                };
                paymentInstrumentEntry.Properties = new[] { paymentInstrumentEntryP1, paymentInstrumentEntryP2, paymentInstrumentEntryP3 };

                using (var entryMessageWriter = new ODataMessageWriter(batchChangesetOperation1, writerSettings, Model))
                {
                    var odataEntryWriter = entryMessageWriter.CreateODataResourceWriter(myPaymentInstrumentSet, paymentInstrumentType);
                    odataEntryWriter.WriteStart(paymentInstrumentEntry);
                    odataEntryWriter.WriteEnd();
                }

                //Changeset end.
                batchWriter.WriteEndChangeset();

                //Another Get request.

                var batchOperation2 = batchWriter.CreateOperationRequestMessage("GET", new Uri(ServiceBaseUri + "Accounts(103)/MyPaymentInstruments(103901)/BillingStatements(103901001)"), null, option);
                batchOperation2.SetHeader("Accept", "application/json;odata.metadata=full");

                //Batch end.
                batchWriter.WriteEndBatch();
            }

            var responseMessage = requestMessage.GetResponse();

            Assert.AreEqual(200, responseMessage.StatusCode);

            using (var innerMessageReader = new ODataMessageReader(responseMessage, readerSettings, Model))
            {
                var batchReader      = innerMessageReader.CreateODataBatchReader();
                int batchOperationId = 0;

                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Initial:
                        break;

                    case ODataBatchReaderState.ChangesetStart:
                        break;

                    case ODataBatchReaderState.ChangesetEnd:
                        break;

                    case ODataBatchReaderState.Operation:
                        ODataBatchOperationResponseMessage operationResponse = batchReader.CreateOperationResponseMessage();

                        using (var operationResponseReader = new ODataMessageReader(operationResponse, readerSettings, Model))
                        {
                            if (batchOperationId == 0)
                            {
                                // the first response message is a feed
                                var feedReader = operationResponseReader.CreateODataResourceSetReader();

                                Assert.AreEqual(200, operationResponse.StatusCode);
                                List <ODataResource> pis = new List <ODataResource>();
                                while (feedReader.Read())
                                {
                                    switch (feedReader.State)
                                    {
                                    case ODataReaderState.ResourceEnd:
                                        ODataResource entry = feedReader.Item as ODataResource;
                                        Assert.IsNotNull(entry);
                                        pis.Add(entry);
                                        break;
                                    }
                                }
                                Assert.AreEqual(ODataReaderState.Completed, feedReader.State);
                                Assert.AreEqual(3, pis.Count);
                            }
                            else if (batchOperationId == 1)
                            {
                                // the second response message is a creation response
                                var entryReader = operationResponseReader.CreateODataResourceReader();

                                Assert.AreEqual(201, operationResponse.StatusCode);
                                List <ODataResource> pis = new List <ODataResource>();
                                while (entryReader.Read())
                                {
                                    switch (entryReader.State)
                                    {
                                    case ODataReaderState.ResourceEnd:
                                        ODataResource entry = entryReader.Item as ODataResource;
                                        Assert.IsNotNull(entry);
                                        pis.Add(entry);
                                        break;
                                    }
                                }
                                Assert.AreEqual(ODataReaderState.Completed, entryReader.State);
                                Assert.AreEqual(1, pis.Count);
                                Assert.AreEqual(102910, pis[0].Properties.Single(p => p.Name == "PaymentInstrumentID").Value);
                            }
                            else if (batchOperationId == 2)
                            {
                                // the third response message is an entry
                                var entryReader = operationResponseReader.CreateODataResourceReader();

                                Assert.AreEqual(200, operationResponse.StatusCode);
                                List <ODataResource> statements = new List <ODataResource>();
                                while (entryReader.Read())
                                {
                                    switch (entryReader.State)
                                    {
                                    case ODataReaderState.ResourceEnd:
                                        ODataResource entry = entryReader.Item as ODataResource;
                                        Assert.IsNotNull(entry);
                                        statements.Add(entry);
                                        break;
                                    }
                                }
                                Assert.AreEqual(ODataReaderState.Completed, entryReader.State);
                                Assert.AreEqual(1, statements.Count);
                                Assert.AreEqual(103901001, statements[0].Properties.Single(p => p.Name == "StatementID").Value);
                            }
                        }
                        batchOperationId++;
                        break;
                    }
                }
                Assert.AreEqual(ODataBatchReaderState.Completed, batchReader.State);
            }
        }
예제 #29
0
        public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage)
        {
            responseMessage.SetStatusCode(HttpStatusCode.OK);

            using (var batchRequestMessageWriter = this.CreateMessageWriter(responseMessage))
            {
                var batchWriter = batchRequestMessageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                using (var batchRequestMessageReader = this.CreateMessageReader(requestMessage))
                {
                    var batchReader = batchRequestMessageReader.CreateODataBatchReader();

                    while (batchReader.Read())
                    {
                        switch (batchReader.State)
                        {
                        case ODataBatchReaderState.Initial:
                            break;

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

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

                        case ODataBatchReaderState.Operation:
                            ODataBatchOperationRequestMessage operationRequestMessage =
                                batchReader.CreateOperationRequestMessage();

                            ODataBatchOperationResponseMessage operationResponseMessage =
                                batchWriter.CreateOperationResponseMessage(operationRequestMessage.ContentId);

                            HttpMethod method = Utility.CreateHttpMethod(operationRequestMessage.Method);

                            switch (method)
                            {
                            case HttpMethod.GET:
                                new QueryHandler(this, operationRequestMessage.Url, operationRequestMessage.Headers).Process(operationRequestMessage, operationResponseMessage);
                                break;

                            case HttpMethod.POST:
                                new CreateHandler(this, operationRequestMessage.Url, operationRequestMessage.Headers).Process(operationRequestMessage, operationResponseMessage);
                                break;

                            case HttpMethod.DELETE:
                                new DeleteHandler(this, operationRequestMessage.Url, operationRequestMessage.Headers).Process(operationRequestMessage, operationResponseMessage);
                                break;

                            case HttpMethod.PATCH:
                            case HttpMethod.PUT:
                                new UpdateHandler(this, method, operationRequestMessage.Url, operationRequestMessage.Headers).Process(operationRequestMessage, operationResponseMessage);
                                break;

                            default:
                                new ErrorHandler(this, Utility.BuildException(HttpStatusCode.MethodNotAllowed)).Process(operationRequestMessage, operationResponseMessage);
                                break;
                            }

                            break;
                        }
                    }
                }

                batchWriter.WriteEndBatch();
            }
        }
예제 #30
0
        internal static Tuple <HttpWebRequest, Stream> BuildRequestForTableBatchOperation(Uri uri, UriQueryBuilder builder, IBufferManager bufferManager, int?timeout, string tableName, TableBatchOperation batch, bool useVersionHeader, OperationContext ctx, TableRequestOptions options, string accountName)
        {
            HttpWebRequest     msg           = BuildRequestCore(NavigationHelper.AppendPathToSingleUri(uri, "$batch"), builder, "POST", timeout, useVersionHeader, ctx);
            TablePayloadFormat payloadFormat = options.PayloadFormat.Value;

            Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat);

            // create the writer, indent for readability of the examples.
            ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings()
            {
                CheckCharacters = false,                              // sets this flag on the XmlWriter for ATOM
                Version         = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry
            };

            HttpWebRequestAdapterMessage adapterMsg = new HttpWebRequestAdapterMessage(msg, bufferManager);

            // Start Batch
            ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings);
            ODataBatchWriter   batchWriter = odataWriter.CreateODataBatchWriter();

            batchWriter.WriteStartBatch();

            bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve;

            // Query operations should not be inside changeset in payload
            if (!isQuery)
            {
                // Start Operation
                batchWriter.WriteStartChangeset();
                batchWriter.Flush();
            }

            foreach (TableOperation operation in batch)
            {
                string httpMethod = operation.HttpMethod;
                if (operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge)
                {
                    options.AssertNoEncryptionPolicyOrStrictMode();
                    httpMethod = "MERGE";
                }

                ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(uri, tableName));
                SetAcceptAndContentTypeForODataBatchMessage(mimePartMsg, payloadFormat);

                // etag
                if (operation.OperationType == TableOperationType.Delete ||
                    operation.OperationType == TableOperationType.Replace ||
                    operation.OperationType == TableOperationType.Merge)
                {
                    mimePartMsg.SetHeader("If-Match", operation.Entity.ETag);
                }

                // Prefer header
                if (operation.OperationType == TableOperationType.Insert)
                {
                    mimePartMsg.SetHeader("Prefer", operation.EchoContent ? "return-content" : "return-no-content");
                }

                if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve)
                {
                    using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings, new TableStorageModel(accountName)))
                    {
                        // Write entity
                        ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter();
                        WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter, options);
                    }
                }
            }

            if (!isQuery)
            {
                // End Operation
                batchWriter.WriteEndChangeset();
            }

            // End Batch
            batchWriter.WriteEndBatch();
            batchWriter.Flush();

            return(new Tuple <HttpWebRequest, Stream>(adapterMsg.GetPopulatedMessage(), adapterMsg.GetStream()));
        }
예제 #31
0
        /// <summary>
        /// Create a batch request that contains atomic groups.
        /// </summary>
        /// <param name="atomicGroupIdFromRequest">Output string for the first atomic group id from the batch created.</param>
        /// <param name="atomicGroupAIdFromRequest">Output string for the second atomic group id from the batch created.</param>
        /// <returns>Stream containing the batch request.</returns>
        private byte[] CreateBatchRequestWithMultipleAtomicGroups(
            out string atomicGroupIdFromRequest,
            out string atomicGroupAIdFromRequest)
        {
            MemoryStream stream = new MemoryStream();

            IODataRequestMessage requestMessage = new InMemoryMessage {
                Stream = stream
            };

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

            settings.BaseUri = new Uri(serviceDocumentUri);

            using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings))
            {
                ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter();
                batchWriter.WriteStartBatch();

                // Lexical scope for first half: query ("3"), create("1"), patch("2")
                {
                    // Query operation
                    ODataBatchOperationRequestMessage queryOperationMessage =
                        batchWriter.CreateOperationRequestMessage("GET", new Uri(serviceDocumentUri + "MySingleton"),
                                                                  "3");

                    queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full");

                    batchWriter.WriteStartChangeset();

                    // Create operation.
                    ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage
                                                                               (
                        "PUT",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        "1");

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage))
                    {
                        ODataWriter   entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        ODataResource entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[]
                            {
                                new ODataProperty()
                                {
                                    Name = "WebId", Value = 10
                                },
                                new ODataProperty()
                                {
                                    Name  = "Name",
                                    Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest"
                                }
                            }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    // A PATCH operation that depends on the preceding PUT operation.
                    string[] dependsOnIds = new string[] { "1" };

                    ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage
                                                                               (
                        "PATCH",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1")),
                        "2",
                        BatchPayloadUriOption.AbsoluteUri,
                        dependsOnIds);

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                    {
                        var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        var entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[] { new ODataProperty()
                                                 {
                                                     Name = "WebId", Value = 11
                                                 } }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId);
                    batchWriter.WriteEndChangeset();

                    atomicGroupIdFromRequest = createOperationMessage.GroupId;
                }

                // Lexical scope for second half: create("1A"), patch("2A"), query("3A")
                {
                    batchWriter.WriteStartChangeset();

                    // Create operation.
                    ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage
                                                                               (
                        "PUT",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")),
                        "1A");

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage))
                    {
                        ODataWriter   entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        ODataResource entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[]
                            {
                                new ODataProperty()
                                {
                                    Name = "WebId", Value = 10
                                },
                                new ODataProperty()
                                {
                                    Name  = "Name",
                                    Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest"
                                }
                            }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    // A PATCH operation that depends on the preceding PUT operation.
                    string[] dependsOnIds = new string[] { "1A" };

                    ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage
                                                                               (
                        "PATCH",
                        new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1A")),
                        "2A",
                        BatchPayloadUriOption.AbsoluteUri,
                        dependsOnIds);

                    using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage))
                    {
                        var entryWriter = operationMessageWriter.CreateODataResourceWriter();
                        var entry       = new ODataResource()
                        {
                            TypeName   = "NS.Web",
                            Properties = new[] { new ODataProperty()
                                                 {
                                                     Name = "WebId", Value = 11
                                                 } }
                        };
                        entryWriter.WriteStart(entry);
                        entryWriter.WriteEnd();
                    }

                    Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId);
                    batchWriter.WriteEndChangeset();

                    atomicGroupAIdFromRequest = createOperationMessage.GroupId;

                    // Query operation
                    ODataBatchOperationRequestMessage queryOperationMessage =
                        batchWriter.CreateOperationRequestMessage("GET", new Uri(serviceDocumentUri + "MySingleton"),
                                                                  "3A");

                    queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full");
                }

                batchWriter.WriteEndBatch();

                Assert.NotEqual(atomicGroupIdFromRequest,
                                atomicGroupAIdFromRequest);

                stream.Position = 0;
                return(stream.ToArray());
            }
        }