示例#1
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 ODataBatchOperationResponseMessage CreateOperationResponseMessageImplementation()
        {
            string responseLine = this.batchStream.ReadFirstNonEmptyLine();

            int statusCode = this.ParseResponseLine(responseLine);

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

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

            // In responses we don't need to use our batch URL resolver, since there are no cross referencing URLs
            // so use the URL resolver from the batch message instead.
            // We don't have correlation of changeset boundary between request and response messages in
            // changesets, so use null value for groupId.
            ODataBatchOperationResponseMessage responseMessage = BuildOperationResponseMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                statusCode,
                headers,
                this.currentContentId,
                /*groupId*/ null);

            //// NOTE: Content-IDs for cross referencing are only supported in request messages; in responses
            ////       we allow a Content-ID header but don't process it (i.e., don't add the content ID to the URL resolver).
            this.currentContentId = null;
            return(responseMessage);
        }
        /// <summary>
        /// Writes a single OData batch response.
        /// </summary>
        /// <param name="writer">The <see cref="ODataBatchWriter"/>.</param>
        /// <param name="context">The message context.</param>
        public static async Task WriteMessageAsync(ODataBatchWriter writer, HttpContext context)
        {
            if (writer == null)
            {
                throw Error.ArgumentNull("writer");
            }
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            string contentId = (context.Request != null) ? context.Request.GetODataContentId() : String.Empty;

            ODataBatchOperationResponseMessage batchResponse = writer.CreateOperationResponseMessage(contentId);

            batchResponse.StatusCode = context.Response.StatusCode;

            foreach (KeyValuePair <string, StringValues> header in context.Response.Headers)
            {
                batchResponse.SetHeader(header.Key, String.Join(",", header.Value.ToArray()));
            }

            if (context.Response.Body != null && context.Response.Body.Length != 0)
            {
                using (Stream stream = batchResponse.GetStream())
                {
                    context.RequestAborted.ThrowIfCancellationRequested();
                    context.Response.Body.Seek(0L, SeekOrigin.Begin);
                    await context.Response.Body.CopyToAsync(stream);
                }
            }
        }
示例#3
0
        /// <summary>
        /// Writes a single OData batch response.
        /// </summary>
        /// <param name="writer">The <see cref="ODataBatchWriter"/>.</param>
        /// <param name="response">The response message.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task object representing writing the given batch response using the given writer.</returns>
        public static async Task WriteMessageAsync(ODataBatchWriter writer, HttpResponseMessage response,
                                                   CancellationToken cancellationToken)
        {
            if (writer == null)
            {
                throw Error.ArgumentNull("writer");
            }
            if (response == null)
            {
                throw Error.ArgumentNull("response");
            }

            ODataBatchOperationResponseMessage batchResponse = writer.CreateOperationResponseMessage();

            batchResponse.StatusCode = (int)response.StatusCode;

            foreach (KeyValuePair <string, IEnumerable <string> > header in response.Headers)
            {
                batchResponse.SetHeader(header.Key, String.Join(",", header.Value));
            }

            if (response.Content != null)
            {
                foreach (KeyValuePair <string, IEnumerable <string> > header in response.Content.Headers)
                {
                    batchResponse.SetHeader(header.Key, String.Join(",", header.Value));
                }

                using (Stream stream = batchResponse.GetStream())
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    await response.Content.CopyToAsync(stream);
                }
            }
        }
示例#4
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(ODataBatchOperationResponseMessage responseMessage, WriterTestConfiguration testConfiguration)
 {
     if (testConfiguration.Synchronous)
     {
         return(responseMessage.GetStream());
     }
     else
     {
         var t = responseMessage.GetStreamAsync();
         t.Wait();
         return(t.Result);
     }
 }
示例#6
0
        private void WriteOperation(ODataBatchWriter writer, OeOperationMessage operation)
        {
            ODataBatchOperationResponseMessage operationMessage = writer.CreateOperationResponseMessage(operation.ContentId);

            operationMessage.SetHeader("Location", operation.RequestUrl.AbsoluteUri);
            operationMessage.SetHeader(ODataConstants.ContentTypeHeader, operation.ContentType);
            operationMessage.StatusCode = (int)operation.StatusCode;

            if (operation.StatusCode != HttpStatusCode.NoContent)
            {
                using (Stream stream = operationMessage.GetStream())
                    WriteEntity(stream, operation.EntityItem);
            }
        }
示例#7
0
        private async Task WriteOperation(ODataBatchWriter writer, OeOperationMessage operation)
        {
            ODataBatchOperationResponseMessage operationMessage = await writer.CreateOperationResponseMessageAsync(operation.ContentId);

            operationMessage.SetHeader("Location", operation.RequestUrl.AbsoluteUri);
            operationMessage.SetHeader(ODataConstants.ContentTypeHeader, operation.ContentType);
            operationMessage.StatusCode = (int)operation.StatusCode;

            if (operation.StatusCode != HttpStatusCode.NoContent)
            {
                using (Stream stream = await operationMessage.GetStreamAsync())
                    await WriteEntity(operation.EntitySet, operation.Entry, stream);
            }
        }
示例#8
0
        /// <summary>
        /// Writes a single OData batch response.
        /// </summary>
        /// <param name="writer">The <see cref="ODataBatchWriter"/>.</param>
        /// <param name="context">The message context.</param>
        /// <param name="asyncWriter">Whether or not the writer is in async mode. </param>
        public static async Task WriteMessageAsync(ODataBatchWriter writer, HttpContext context, bool asyncWriter)
        {
            if (writer == null)
            {
                throw Error.ArgumentNull("writer");
            }
            if (context == null)
            {
                throw Error.ArgumentNull("context");
            }

            string contentId = (context.Request != null) ? context.Request.GetODataContentId() : String.Empty;

            ODataBatchOperationResponseMessage batchResponse = asyncWriter ?
                                                               await writer.CreateOperationResponseMessageAsync(contentId) :
                                                               writer.CreateOperationResponseMessage(contentId);

            batchResponse.StatusCode = context.Response.StatusCode;

            foreach (KeyValuePair <string, StringValues> header in context.Response.Headers)
            {
                batchResponse.SetHeader(header.Key, String.Join(",", header.Value.ToArray()));
            }

            if (context.Response.Body != null && context.Response.Body.Length != 0)
            {
                using (Stream stream = asyncWriter ? await batchResponse.GetStreamAsync() : batchResponse.GetStream())
                {
                    context.RequestAborted.ThrowIfCancellationRequested();
                    context.Response.Body.Seek(0L, SeekOrigin.Begin);
                    await context.Response.Body.CopyToAsync(stream);

                    // Close and release the stream for the individual response
                    ODataBatchStream batchStream = context.Response.Body as ODataBatchStream;
                    if (batchStream != null)
                    {
                        if (asyncWriter)
                        {
                            await batchStream.InternalDisposeAsync();
                        }
                        else
                        {
                            batchStream.InternalDispose();
                        }
                    }
                }
            }
        }
        private void ClientReadBatchResponse(byte[] responsePayload, string expectedAtomicGroupId, string expectedAtomicGroupAId)
        {
            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

            responseMessage.SetHeader("Content-Type", batchContentTypeApplicationJson);
            using (var messageReader = new ODataMessageReader(responseMessage, new ODataMessageReaderSettings(), this.userModel))
            {
                var batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        ODataBatchOperationResponseMessage operationMessage = batchReader.CreateOperationResponseMessage();
                        string responseId = operationMessage.ContentId;
                        if (responseId.Equals("1") || responseId.Equals("2"))
                        {
                            // Verify the group id of the responses is correlated to the group id from the data modification requests.
                            Assert.Equal(operationMessage.GroupId, expectedAtomicGroupId);
                            Assert.True(operationMessage.StatusCode == 201 || operationMessage.StatusCode == 204);
                        }
                        else if (responseId.Equals("1A") || responseId.Equals("2A"))
                        {
                            // Verify the group id of the responses is correlated to the group id from the data modification requests.
                            Assert.Equal(operationMessage.GroupId, expectedAtomicGroupAId);
                            Assert.True(operationMessage.StatusCode == 201 || operationMessage.StatusCode == 204);
                        }
                        else if (responseId.Equals("3") || responseId.Equals("3A"))
                        {
                            // Verify the group id of the query response.
                            Assert.Null(operationMessage.GroupId);
                        }
                        else
                        {
                            Assert.True(false, "Unexpected response id received: " + responseId);
                        }
                        break;

                    default:
                        break;
                    }
                }
            }
        }
示例#10
0
        private void ClientReadSingletonBatchResponse(byte[] responsePayload, string batchContentType)
        {
            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

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

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

                            // The only two messages with HTTP-200 response codes are the two GET requests with content id value of null.
                            // Verify that: for multipart batch the content id of the response is matching that of the request;
                            // for Json batch the content id of the response is not null.
                            Assert.True(
                                (batchReader is ODataJsonLightBatchReader && operationMessage.ContentId != null) ||
                                (batchReader is ODataMultipartMixedBatchReader && operationMessage.ContentId == null));
                        }
                        break;
                    }
                }
            }
        }
示例#11
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 ODataBatchOperationResponseMessage CreateOperationResponseMessageImplementation()
        {
            this.operationState = OperationState.MessageCreated;

            string responseLine = this.batchStream.ReadFirstNonEmptyLine();

            int statusCode = this.ParseResponseLine(responseLine);

            // Read all headers and create the response 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;
                    }
                }
            }

            // In responses we don't need to use our batch URL resolver, since there are no cross referencing URLs
            // so use the URL resolver from the batch message instead.
            ODataBatchOperationResponseMessage responseMessage = ODataBatchOperationResponseMessage.CreateReadMessage(
                this.batchStream,
                statusCode,
                headers,
                this.contentIdToAddOnNextRead,
                /*operationListener*/ this,
                this.urlResolver.BatchMessageUrlResolver);

            //// NOTE: Content-IDs for cross referencing are only supported in request messages; in responses
            ////       we allow a Content-ID header but don't process it (i.e., don't add the content ID to the URL resolver).

            return(responseMessage);
        }
        /// <summary>
        /// Creates an operation response message that can be used to read the operation content from.
        /// </summary>
        /// <param name="batchReaderStream">The batch stream underyling the operation response message.</param>
        /// <param name="statusCode">The status code to use for the operation response message.</param>
        /// <param name="headers">The headers to use for the operation response message.</param>
        /// <param name="contentId">The content-ID for the operation response message.</param>
        /// <param name="operationListener">The operation listener.</param>
        /// <param name="urlResolver">The (optional) URL resolver for the message to create.</param>
        /// <returns>An <see cref="ODataBatchOperationResponseMessage"/> that can be used to read the operation content.</returns>
        internal static ODataBatchOperationResponseMessage CreateReadMessage(
            ODataBatchReaderStream batchReaderStream,
            int statusCode,
            ODataBatchOperationHeaders headers,
            string contentId,
            IODataBatchOperationListener operationListener,
            IODataUrlResolver urlResolver)
        {
            Debug.Assert(batchReaderStream != null, "batchReaderStream != null");
            Debug.Assert(operationListener != null, "operationListener != null");

            Func <Stream> streamCreatorFunc = () => ODataBatchUtils.CreateBatchOperationReadStream(batchReaderStream, headers, operationListener);
            ODataBatchOperationResponseMessage responseMessage =
                new ODataBatchOperationResponseMessage(streamCreatorFunc, headers, operationListener, contentId, urlResolver, /*writing*/ false);

            responseMessage.statusCode = statusCode;
            return(responseMessage);
        }
示例#13
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);
        }
示例#14
0
        /// <summary>
        /// Set the response stream.
        /// </summary>
        /// <param name ="message">The message that we are setting the stream for.</param>
        /// <param name="stream">Stream to which the response needs to be written.</param>
        internal static void SetStream(this IODataResponseMessage message, Stream stream)
        {
            AstoriaResponseMessage             astoriaResponseMessage = message as AstoriaResponseMessage;
            ODataBatchOperationResponseMessage batchResponseMessage   = message as ODataBatchOperationResponseMessage;

            if (astoriaResponseMessage != null)
            {
                Debug.Assert(stream != null, "When we call SetStream on a non-batch response message, the stream shouldn't be null.");
                astoriaResponseMessage.SetStream(stream);
            }
            else if (batchResponseMessage != null)
            {
                Debug.Assert(stream == null, "When we call SetStream, if we are in a batch operation, then the stream should be null.");
            }
            else
            {
                Debug.Fail("SetStream called on an unknown message type.");
            }
        }
        private void ClientReadBatchResponse(byte[] responsePayload, BodyContentType bodyContentType)
        {
            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

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

                                Assert.Equal(operationMessageBody.Length, sampleBytes.Length);
                                foreach (byte samplebyte in sampleBytes)
                                {
                                    Assert.Equal(samplebyte, operationMessageBody.ReadByte());
                                }
                            }
                        }
                        else
                        {
                            Assert.True(201 == operationMessage.StatusCode);
                        }
                        break;
                    }
                }
            }
        }
示例#16
0
        internal static void SetResponseHeadersForBatchRequests(ODataBatchOperationResponseMessage operationResponseMessage, BatchServiceHost batchHost)
        {
            IDataServiceHost2 host = batchHost;

            operationResponseMessage.StatusCode = host.ResponseStatusCode;
            if (batchHost.ContentId != null)
            {
                operationResponseMessage.SetHeader("Content-ID", batchHost.ContentId);
            }
            WebHeaderCollection responseHeaders = host.ResponseHeaders;

            foreach (string str in responseHeaders.AllKeys)
            {
                string str2 = responseHeaders[str];
                if (!string.IsNullOrEmpty(str2))
                {
                    operationResponseMessage.SetHeader(str, str2);
                }
            }
        }
示例#17
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationResponseMessage"/> for reading the content of a
        /// batch response.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch response from.</returns>
        protected override ODataBatchOperationResponseMessage CreateOperationResponseMessageImplementation()
        {
            Debug.Assert(this.mode == ReaderMode.Responses, "this.mode == ReaderMode.Responses");
            Debug.Assert(this.messagePropertiesCache != null, "this.responsePropertiesCache != null");

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

            int statusCode = (int)
                             this.messagePropertiesCache.GetPropertyValue(ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameStatus);

            string contentId = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameId);

            string groupId = (string)this.messagePropertiesCache.GetPropertyValue(
                ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameAtomicityGroup);

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

            // Reset the response 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;

            // In responses we don't need to use our batch URL resolver, since there are no cross referencing URLs
            // so use the URL resolver from the batch message instead.
            ODataBatchOperationResponseMessage responseMessage = BuildOperationResponseMessage(
                () => bodyContentStream,
                statusCode,
                headers,
                contentId,
                groupId);

            //// NOTE: Content-IDs for cross referencing are only supported in request messages; in responses
            //// we allow a Content-ID header but don't process it (i.e., don't add the content ID to the URL resolver).
            return(responseMessage);
        }
示例#18
0
        private void ClientReadBatchResponse(string batchContentType, byte[] responsePayload)
        {
            Debug.Assert(!string.IsNullOrEmpty(batchContentType), "!string.IsNullOrEmpty(batchContentType)");

            IODataResponseMessage responseMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(responsePayload)
            };

            responseMessage.SetHeader("Content-Type", batchContentType);
            using (var messageReader = new ODataMessageReader(responseMessage, new ODataMessageReaderSettings(), this.userModel))
            {
                var batchReader = messageReader.CreateODataBatchReader();
                while (batchReader.Read())
                {
                    switch (batchReader.State)
                    {
                    case ODataBatchReaderState.Operation:
                        ODataBatchOperationResponseMessage operationMessage = batchReader.CreateOperationResponseMessage();
                        if (operationMessage.StatusCode == 200)
                        {
                            using (ODataMessageReader innerMessageReader = new ODataMessageReader(
                                       operationMessage, new ODataMessageReaderSettings(), this.userModel))
                            {
                                ODataReader reader = innerMessageReader.CreateODataResourceReader();

                                while (reader.Read())
                                {
                                }
                            }
                        }
                        break;

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

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

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

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

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

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

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

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

                    currentResult.HttpStatusCode = mimePartResponseMessage.StatusCode;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    index++;

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

            return(result);
        }
        public void AsyncBatchRequestTest()
        {
            var writerSettings = new ODataMessageWriterSettings();

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

            #region send a batch request with respond-async preference

            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.PreferHeader().RespondAsync = true; //Request the service to process asynchronously.
            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);
                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");
                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);
                batchOperation2.SetHeader("Accept", "application/json;odata.metadata=full");

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

            var responseMessage = requestMessage.GetResponse();

            #endregion

            #region request the status monitor resource

            Assert.Equal(202, responseMessage.StatusCode);
            string monitorResource = responseMessage.GetHeader("Location");
            Assert.False(string.IsNullOrWhiteSpace(monitorResource));

            var statusCheckRequest1  = new HttpWebRequestMessage(new Uri(monitorResource));
            var statusCheckResponse1 = statusCheckRequest1.GetResponse();
            Assert.Equal(202, statusCheckResponse1.StatusCode);
            monitorResource = statusCheckResponse1.GetHeader("Location");
            Assert.False(string.IsNullOrWhiteSpace(monitorResource));

            //The request takes 5 seconds to finish in service, so we wait for 6 seconds.
            Thread.Sleep(6000);
            var statusCheckRequest2  = new HttpWebRequestMessage(new Uri(monitorResource));
            var statusCheckResponse2 = statusCheckRequest2.GetResponse();
            Assert.Equal(200, statusCheckResponse2.StatusCode);

            #endregion

            #region read and verify the response

            using (var messageReader = new ODataMessageReader(statusCheckResponse2, readerSettings, Model))
            {
                var asyncReader  = messageReader.CreateODataAsynchronousReader();
                var innerMessage = asyncReader.CreateResponseMessage();

                Assert.Equal(200, innerMessage.StatusCode);
                using (var innerMessageReader = new ODataMessageReader(innerMessage, 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.Equal(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.NotNull(entry);
                                            pis.Add(entry);
                                            break;
                                        }
                                    }
                                    Assert.Equal(ODataReaderState.Completed, feedReader.State);
                                    Assert.Equal(3, pis.Count);
                                }
                                else if (batchOperationId == 1)
                                {
                                    // the second response message is a creation response
                                    var entryReader = operationResponseReader.CreateODataResourceReader();

                                    Assert.Equal(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.NotNull(entry);
                                            pis.Add(entry);
                                            break;
                                        }
                                    }
                                    Assert.Equal(ODataReaderState.Completed, entryReader.State);
                                    Assert.Single(pis);
                                    Assert.Equal(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.Equal(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.NotNull(entry);
                                            statements.Add(entry);
                                            break;
                                        }
                                    }
                                    Assert.Equal(ODataReaderState.Completed, entryReader.State);
                                    Assert.Single(statements);
                                    Assert.Equal(103901001, statements[0].Properties.Single(p => p.Name == "StatementID").Value);
                                }
                            }
                            batchOperationId++;
                            break;
                        }
                    }
                    Assert.Equal(ODataBatchReaderState.Completed, batchReader.State);
                }
            }

            #endregion
        }
示例#21
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);
            }
        }
示例#22
0
        internal static IList <TableResult> TableBatchOperationPostProcess(IList <TableResult> result, TableBatchOperation batch, RESTCommand <IList <TableResult> > cmd, HttpWebResponse resp, OperationContext ctx)
        {
            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings();

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

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

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

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

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

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

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

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

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

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

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

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

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

                        string indexString = Convert.ToString(index);

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

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

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

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

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

                    index++;

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

            return(result);
        }
        private byte[] ServiceReadReferenceUriBatchRequestAndWriteResponse(byte[] requestPayload)
        {
            IODataRequestMessage requestMessage = new InMemoryMessage()
            {
                Stream = new MemoryStream(requestPayload)
            };

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

            settings.BaseUri = new Uri(serviceDocumentUri);

            byte[] responseBytes = null;

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

                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

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

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

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

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

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

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

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

                            break;

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

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

                    batchWriter.WriteEndBatch();

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

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

            requestMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson);

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

                IODataResponseMessage responseMessage = new InMemoryMessage {
                    Stream = responseStream
                };

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

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

                        ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage();

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

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

                        break;

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

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

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

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

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

            MemoryStream responseStream = new MemoryStream();

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

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

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

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

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

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

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

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

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

                        operationIdx++;
                        break;

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

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

                batchWriter.WriteEndBatch();
            }

            responseStream.Position = 0;
            return(responseStream.ToArray());
        }
 private static Stream GetMessageStream(ODataBatchOperationResponseMessage responseMessage, WriterTestConfiguration testConfiguration)
 {
     if (testConfiguration.Synchronous)
     {
         return responseMessage.GetStream();
     }
     else
     {
         var t = responseMessage.GetStreamAsync();
         t.Wait();
         return t.Result;
     }
 }
示例#27
0
 internal ODataBatchOperationResponseMessage GetOperationResponseMessage()
 {
     return(this.operationMessage ?? (this.operationMessage = this.writer.CreateOperationResponseMessage()));
 }
        /// <summary>
        /// Creates an operation response message that can be used to read the operation content from.
        /// </summary>
        /// <param name="batchReaderStream">The batch stream underyling the operation response message.</param>
        /// <param name="statusCode">The status code to use for the operation response message.</param>
        /// <param name="headers">The headers to use for the operation response message.</param>
        /// <param name="contentId">The content-ID for the operation response message.</param>
        /// <param name="operationListener">The operation listener.</param>
        /// <param name="urlResolver">The (optional) URL resolver for the message to create.</param>
        /// <returns>An <see cref="ODataBatchOperationResponseMessage"/> that can be used to read the operation content.</returns>
        internal static ODataBatchOperationResponseMessage CreateReadMessage(
            ODataBatchReaderStream batchReaderStream,
            int statusCode,
            ODataBatchOperationHeaders headers,
            string contentId,
            IODataBatchOperationListener operationListener,
            IODataUrlResolver urlResolver)
        {
            Debug.Assert(batchReaderStream != null, "batchReaderStream != null");
            Debug.Assert(operationListener != null, "operationListener != null");

            Func<Stream> streamCreatorFunc = () => ODataBatchUtils.CreateBatchOperationReadStream(batchReaderStream, headers, operationListener);
            ODataBatchOperationResponseMessage responseMessage =
                new ODataBatchOperationResponseMessage(streamCreatorFunc, headers, operationListener, contentId, urlResolver, /*writing*/ false);
            responseMessage.statusCode = statusCode;
            return responseMessage;
        }
示例#29
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);
            }
        }
示例#30
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();
            }
        }
示例#31
0
        /// <summary>
        /// Processed the operation response reported by the batch reader.
        /// This is a side-effecting method that is tied deeply to how it is used in the batch processing pipeline.
        /// </summary>
        /// <param name="batchReader">The batch reader to get the operation response from.</param>
        /// <param name="isChangesetOperation">True if the current operation is inside a changeset (implying CUD, not query)</param>
        /// <returns>An exception if the operation response is an error response, null for success response.</returns>
        private Exception ProcessCurrentOperationResponse(ODataBatchReader batchReader, bool isChangesetOperation)
        {
            Debug.Assert(batchReader != null, "batchReader != null");
            Debug.Assert(batchReader.State == ODataBatchReaderState.Operation, "This method requires the batch reader to be on an operation.");

            ODataBatchOperationResponseMessage operationResponseMessage = batchReader.CreateOperationResponseMessage();
            Descriptor descriptor = null;

            if (isChangesetOperation)
            {
                // We need to peek at the content-Id before handing the response to the user, so we can expose the Descriptor them.
                // We're OK with this exception to our general rule of not using them before ReceivingResponse event is fired.
                this.entryIndex = this.ValidateContentID(operationResponseMessage.ContentId);
                descriptor      = this.ChangedEntries[entryIndex];
            }

            // If we hit en error inside a batch, we will never expose a descriptor since we don't know which one to return.
            // The descriptor we fetched above based on the content-ID is bogus because the server returns an errounous content-id when
            // it hits an error inside batch.
            if (!WebUtil.SuccessStatusCode((HttpStatusCode)operationResponseMessage.StatusCode))
            {
                descriptor = null;
            }

            this.RequestInfo.Context.FireReceivingResponseEvent(new ReceivingResponseEventArgs(operationResponseMessage, descriptor, true));

            // We need to know if the content of the operation response is empty or not.
            // We also need to cache the entire content, since in case of GET response the response itself will be parsed
            // lazily and so it can happen that we will move the batch reader after this operation before we actually read
            // the content of the operation.
            Stream originalOperationResponseContentStream = operationResponseMessage.GetStream();

            if (originalOperationResponseContentStream == null)
            {
                Error.ThrowBatchExpectedResponse(InternalError.NullResponseStream);
            }

            MemoryStream operationResponseContentStream;

            try
            {
                operationResponseContentStream = new MemoryStream();
                WebUtil.CopyStream(originalOperationResponseContentStream, operationResponseContentStream, ref this.streamCopyBuffer);
                operationResponseContentStream.Position = 0;
            }
            finally
            {
                originalOperationResponseContentStream.Dispose();
            }

            this.currentOperationResponse = new CurrentOperationResponse(
                (HttpStatusCode)operationResponseMessage.StatusCode,
                operationResponseMessage.Headers,
                operationResponseContentStream);

            Version responseVersion;
            string  headerName = XmlConstants.HttpODataVersion;

            return(BaseSaveResult.HandleResponse(
                       this.RequestInfo,
                       this.currentOperationResponse.StatusCode,
                       this.currentOperationResponse.Headers.GetHeader(headerName),
                       () => this.currentOperationResponse.ContentStream,
                       false,
                       out responseVersion));
        }
示例#32
0
 /// <summary>
 /// Return the response message for this operation.
 /// </summary>
 /// <returns>ODataBatchOperationResponseMessage instance for this batch operation.</returns>
 internal ODataBatchOperationResponseMessage GetOperationResponseMessage()
 {
     return this.operationMessage ?? (this.operationMessage = this.writer.CreateOperationResponseMessage(this.contentId));
 }