public ODataResource CreateEntry(ODataBatchOperationRequestMessage batchRequest, out IEdmEntitySet entitSet) { if (batchRequest.Method == ODataConstants.MethodDelete) { return(ReadEntityFromUrl(batchRequest.Url, out entitSet)); } String contentType = batchRequest.GetHeader(ODataConstants.ContentTypeHeader); using (Stream stream = batchRequest.GetStream()) return(ReadEntityFromStream(stream, batchRequest.Url, contentType, out entitSet)); }
private static async Task <HttpContext> ReadOperationInternalAsync( ODataBatchReader reader, HttpContext originalContext, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true) { ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync(); HttpContext context = CreateHttpContext(originalContext); HttpRequest request = context.Request; request.Method = batchRequest.Method; request.CopyAbsoluteUrl(batchRequest.Url); // Not using bufferContentStream. Unlike AspNet, AspNetCore cannot guarantee the disposal // of the stream in the context of execution so there is no choice but to copy the stream // from the batch reader. using (Stream stream = batchRequest.GetStream()) { MemoryStream bufferedStream = new MemoryStream(); // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken); bufferedStream.Position = 0; request.Body = bufferedStream; } foreach (var header in batchRequest.Headers) { string headerName = header.Key; string headerValue = header.Value; if (headerName.Trim().ToLowerInvariant() == "prefer") { // in the case of Prefer header, we don't want to overwrite, // instead we merge preferences defined in the individual request with those inherited from the batch request.Headers.TryGetValue(headerName, out StringValues batchReferences); request.Headers[headerName] = MergeIndividualAndBatchPreferences(headerValue, batchReferences); } else { // Copy headers from batch, overwriting any existing headers. request.Headers[headerName] = headerValue; } } request.SetODataBatchId(batchId); request.SetODataContentId(batchRequest.ContentId); if (changeSetId != null && changeSetId.HasValue) { request.SetODataChangeSetId(changeSetId.Value); } return(context); }
private static BatchWriterStatesTestSetupResult GetOperationStream(object message, WriterTestConfiguration testConfiguration) { BatchWriterStatesTestSetupResult result = new BatchWriterStatesTestSetupResult { Message = message }; ODataBatchOperationRequestMessage requestMessage = message as ODataBatchOperationRequestMessage; if (requestMessage != null) { if (testConfiguration.Synchronous) { result.MessageStream = requestMessage.GetStream(); return(result); } else { // TODO: 191417: Enable async Tests on Phone and Silverlight when Product Supports them #if SILVERLIGHT || WINDOWS_PHONE throw new TaupoNotSupportedException("This test is not supported in aSynchronous mode in Silverlight or Phone"); #else var t = requestMessage.GetStreamAsync(); t.Wait(); result.MessageStream = t.Result; return(result); #endif } } ODataBatchOperationResponseMessage responseMessage = message as ODataBatchOperationResponseMessage; if (responseMessage != null) { if (testConfiguration.Synchronous) { result.MessageStream = responseMessage.GetStream(); return(result); } else { // TODO: Enable async Tests on Phone and Silverlight when Product Supports them #if SILVERLIGHT || WINDOWS_PHONE throw new TaupoNotSupportedException("This test is not supported in aSynchronous mode in Silverlight or Phone"); #else var t = responseMessage.GetStreamAsync(); t.Wait(); result.MessageStream = t.Result; return(result); #endif } } return(null); }
private static Stream GetMessageStream(ODataBatchOperationRequestMessage requestMessage, WriterTestConfiguration testConfiguration) { if (testConfiguration.Synchronous) { return(requestMessage.GetStream()); } else { var t = requestMessage.GetStreamAsync(); t.Wait(); return(t.Result); } }
/// <summary> /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation /// in a batch request. /// </summary> /// <returns>The message that can be used to read the content of the batch request operation from.</returns> protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation() { string requestLine = this.batchStream.ReadFirstNonEmptyLine(); string httpMethod; Uri requestUri; this.ParseRequestLine(requestLine, out httpMethod, out requestUri); // Read all headers and create the request message ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders(); if (this.batchStream.ChangeSetBoundary != null) { if (this.currentContentId == null) { headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId); if (this.currentContentId == null) { throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader)); } } } else if (this.InputContext.MessageReaderSettings.Version <= ODataVersion.V4) { // For backward compatibility, don't enforce uniqueness of Content-ID // in MultipartMixed outside of a changeset this.PayloadUriConverter.Reset(); } ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage( () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this), httpMethod, requestUri, headers, this.currentContentId, this.batchStream.ChangeSetBoundary, this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false); if (this.currentContentId != null) { this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId); } this.currentContentId = null; return(requestMessage); }
/// <summary> /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation /// in a batch request. /// </summary> /// <returns>The message that can be used to read the content of the batch request operation from.</returns> private ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation() { this.operationState = OperationState.MessageCreated; string requestLine = this.batchStream.ReadFirstNonEmptyLine(); string httpMethod; Uri requestUri; this.ParseRequestLine(requestLine, out httpMethod, out requestUri); // Read all headers and create the request message ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders(); if (this.batchStream.ChangeSetBoundary != null) { if (this.allowLegacyContentIdBehaviour) { // Add a potential Content-ID header to the URL resolver so that it will be available // to subsequent operations. string contentId; if (this.contentIdToAddOnNextRead == null && headers.TryGetValue(ODataConstants.ContentIdHeader, out contentId)) { if (contentId != null && this.urlResolver.ContainsContentId(contentId)) { throw new ODataException(Strings.ODataBatchReader_DuplicateContentIDsNotAllowed(contentId)); } this.contentIdToAddOnNextRead = contentId; } } if (this.contentIdToAddOnNextRead == null) { throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader)); } } ODataBatchOperationRequestMessage requestMessage = ODataBatchOperationRequestMessage.CreateReadMessage( this.batchStream, httpMethod, requestUri, headers, /*operationListener*/ this, this.contentIdToAddOnNextRead, this.urlResolver); return(requestMessage); }
private byte[] ClientWriteBatchRequest(BodyContentType bodyContentType) { MemoryStream stream = new MemoryStream(); IODataRequestMessage requestMessage = new InMemoryMessage { Stream = stream }; requestMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson); using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage)) { ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); // Write a change set with update operation. batchWriter.WriteStartChangeset(); // Create an update operation in the change set. ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage( "PUT", new Uri(serviceDocumentUri + "MyBlob"), "1"); // Set the content type with explicit character set so that the content string // is flushed into the operation message body stream without byte-order-mark. updateOperationMessage.SetHeader("CoNtEnt-TYPE", GetContentType(bodyContentType)); // Use the message writer to write encoded string content. using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { operationMessageWriter.WriteValue(GetEncodedContentObject(bodyContentType, /*forRequest*/ true)); } batchWriter.WriteEndChangeset(); // Write a query operation. ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage( "GET", new Uri(serviceDocumentUri + "MyBlob"), /*contentId*/ null); // Header modification on inner payload. queryOperationMessage.SetHeader("AcCePt", GetContentType(bodyContentType)); batchWriter.WriteEndBatch(); stream.Position = 0; return(stream.ToArray()); } }
public static OeOperationMessage Create(OeMessageContext context, ODataBatchReader reader) { ODataBatchOperationRequestMessage batchRequest = reader.CreateOperationRequestMessage(); var operation = new OeOperationMessage(batchRequest); if (batchRequest.Method == ODataConstants.MethodDelete) { operation.EntityItem = operation.ReadEntityFromUrl(context); } else { using (Stream stream = batchRequest.GetStream()) operation.EntityItem = operation.ReadEntityFromStream(context, stream); } return(operation); }
private static async Task <HttpRequestMessage> ReadOperationInternalAsync( ODataBatchReader reader, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true) { ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync(); HttpRequestMessage request = new HttpRequestMessage(); request.Method = new HttpMethod(batchRequest.Method); request.RequestUri = batchRequest.Url; if (bufferContentStream) { using (Stream stream = await batchRequest.GetStreamAsync()) { MemoryStream bufferedStream = new MemoryStream(); // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken); bufferedStream.Position = 0; request.Content = new StreamContent(bufferedStream); } } else { request.Content = new LazyStreamContent(() => batchRequest.GetStreamAsync().Result); } foreach (var header in batchRequest.Headers) { string headerName = header.Key; string headerValue = header.Value; if (!request.Headers.TryAddWithoutValidation(headerName, headerValue)) { request.Content.Headers.TryAddWithoutValidation(headerName, headerValue); } } request.SetODataBatchId(batchId); request.SetODataContentId(batchRequest.ContentId); if (changeSetId != null && changeSetId.HasValue) { request.SetODataChangeSetId(changeSetId.Value); } return(request); }
private static void SetAcceptAndContentTypeForODataBatchMessage(ODataBatchOperationRequestMessage mimePartMsg, TablePayloadFormat payloadFormat) { if (payloadFormat == TablePayloadFormat.JsonFullMetadata) { mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonFullMetadataAcceptHeaderValue); mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue); } else if (payloadFormat == TablePayloadFormat.Json) { mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonLightAcceptHeaderValue); mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue); } else { mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadAcceptHeader, Constants.JsonNoMetadataAcceptHeaderValue); mimePartMsg.SetHeader(Constants.HeaderConstants.PayloadContentTypeHeader, Constants.JsonContentTypeHeaderValue); } }
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); }
private static async Task <HttpRequestMessage> ReadOperationInternalAsync(ODataBatchReader reader, Guid batchId, Guid?changeSetId, bool bufferContentStream = true) { ODataBatchOperationRequestMessage batchRequest = reader.CreateOperationRequestMessage(); HttpRequestMessage request = new HttpRequestMessage(); request.Method = new HttpMethod(batchRequest.Method); request.RequestUri = batchRequest.Url; if (bufferContentStream) { using (Stream stream = batchRequest.GetStream()) { MemoryStream bufferedStream = new MemoryStream(); await stream.CopyToAsync(bufferedStream); bufferedStream.Position = 0; request.Content = new StreamContent(bufferedStream); } } else { request.Content = new LazyStreamContent(() => batchRequest.GetStream()); } foreach (var header in batchRequest.Headers) { string headerName = header.Key; string headerValue = header.Value; if (!request.Headers.TryAddWithoutValidation(headerName, headerValue)) { request.Content.Headers.TryAddWithoutValidation(headerName, headerValue); } } request.SetODataBatchId(batchId); if (changeSetId != null && changeSetId.HasValue) { request.SetODataChangeSetId(changeSetId.Value); } return(request); }
/// <summary> /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation /// in a batch request. /// </summary> /// <returns>The message that can be used to read the content of the batch request operation from.</returns> protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation() { string requestLine = this.batchStream.ReadFirstNonEmptyLine(); string httpMethod; Uri requestUri; this.ParseRequestLine(requestLine, out httpMethod, out requestUri); // Read all headers and create the request message ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders(); if (this.batchStream.ChangeSetBoundary != null) { if (this.currentContentId == null) { headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId); if (this.currentContentId == null) { throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader)); } } } ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage( () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this), httpMethod, requestUri, headers, this.currentContentId, this.batchStream.ChangeSetBoundary, this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false); if (this.currentContentId != null) { this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId); } this.currentContentId = null; return(requestMessage); }
private static async Task <HttpContext> ReadOperationInternalAsync( ODataBatchReader reader, HttpContext originalContext, Guid batchId, Guid?changeSetId, CancellationToken cancellationToken, bool bufferContentStream = true) { ODataBatchOperationRequestMessage batchRequest = await reader.CreateOperationRequestMessageAsync(); HttpContext context = CreateHttpContext(originalContext); HttpRequest request = context.Request; request.Method = batchRequest.Method; request.CopyAbsoluteUrl(batchRequest.Url); // Not using bufferContentStream. Unlike AspNet, AspNetCore cannot guarantee the disposal // of the stream in the context of execution so there is no choice but to copy the stream // from the batch reader. using (Stream stream = batchRequest.GetStream()) { MemoryStream bufferedStream = new MemoryStream(); // Passing in the default buffer size of 81920 so that we can also pass in a cancellation token await stream.CopyToAsync(bufferedStream, bufferSize : 81920, cancellationToken : cancellationToken); bufferedStream.Position = 0; request.Body = bufferedStream; } foreach (var header in batchRequest.Headers) { // Copy headers from batch, overwriting any existing headers. string headerName = header.Key; string headerValue = header.Value; request.Headers[headerName] = headerValue; } request.SetODataBatchId(batchId); request.SetODataContentId(batchRequest.ContentId); if (changeSetId != null && changeSetId.HasValue) { request.SetODataChangeSetId(changeSetId.Value); } return(context); }
/// <summary> /// Asynchronously creates an <see cref="ODataBatchOperationRequestMessage"/> for writing an operation of a batch request /// - implementation of the actual functionality. /// </summary> /// <param name="method">The Http method to be used for this request operation.</param> /// <param name="uri">The Uri to be used for this request operation.</param> /// <param name="contentId">The Content-ID value to write in ChangeSet head.</param> /// <param name="payloadUriOption"> /// The format of operation Request-URI, which could be AbsoluteUri, AbsoluteResourcePathAndHost, or RelativeResourcePath.</param> /// <param name="dependsOnIds">The prerequisite request ids of this request. By default its value should be null for Multipart/Mixed /// format and the dependsOnIds implicitly derived per the protocol will be used; Otherwise, non-null will be used as override after /// validation.</param> /// <returns>A task that represents the asynchronous operation. /// The value of the TResult parameter contains an <see cref="ODataBatchOperationRequestMessage"/> /// that can be used to write the request operation.</returns> protected override async Task <ODataBatchOperationRequestMessage> CreateOperationRequestMessageImplementationAsync( string method, Uri uri, string contentId, BatchPayloadUriOption payloadUriOption, IEnumerable <string> dependsOnIds) { // Write pending message data (headers, response line) for a previously unclosed message/request await this.WritePendingMessageDataAsync(true) .ConfigureAwait(false); // Create the new request operation // For Multipart batch format, validate dependsOnIds if it is user explicit input, otherwise skip validation // when it is implicitly derived per protocol. ODataBatchOperationRequestMessage operationRequestMessage = BuildOperationRequestMessage( this.RawOutputContext.OutputStream, method, uri, contentId, this.changeSetBoundary, dependsOnIds); this.SetState(BatchWriterState.OperationCreated); // Write the operation's start boundary string await this.WriteStartBoundaryForOperationAsync() .ConfigureAwait(false); if (contentId != null) { this.dependsOnIdsTracker.AddDependsOnId(contentId); } // Write the headers and request line await ODataMultipartMixedBatchWriterUtils.WriteRequestPreambleAsync( this.RawOutputContext.TextWriter, method, uri, this.RawOutputContext.MessageWriterSettings.BaseUri, changeSetBoundary != null, contentId, payloadUriOption).ConfigureAwait(false); return(operationRequestMessage); }
private void ServiceProcessBatchRequest(ODataJsonBatchPayloadTestCase testCase, ODataVersion version) { string requestPayload = testCase.RequestPayload; ODataJsonBatchPayloadTestCase.ValidateContentType requestMessageContentTypeVerifier = testCase.ContentTypeVerifier; IODataRequestMessage requestMessage = new InMemoryMessage() { Stream = new MemoryStream(Encoding.ASCII.GetBytes(requestPayload)) }; requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson); using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, new ODataMessageReaderSettings() { Version = version, BaseUri = new Uri("http://odata.org") }, this.edmModel)) { ODataBatchReader batchReader = messageReader.CreateODataBatchReader(); int operationIdx = 0; while (batchReader.Read()) { switch (batchReader.State) { case ODataBatchReaderState.Operation: ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage(); // Verify operation message content type processing. requestMessageContentTypeVerifier.Invoke(operationMessage, operationIdx); operationIdx++; break; } } } }
/// <summary> /// Creates an <see cref="ODataBatchOperationRequestMessage"/> for writing an operation of a batch request /// - implementation of the actual functionality. /// </summary> /// <param name="method">The Http method to be used for this request operation.</param> /// <param name="uri">The Uri to be used for this request operation.</param> /// <param name="contentId">The Content-ID value to write in ChangeSet head.</param> /// <param name="payloadUriOption"> /// The format of operation Request-URI, which could be AbsoluteUri, AbsoluteResourcePathAndHost, or RelativeResourcePath.</param> /// <param name="dependsOnIds">The prerequisite request ids of this request.</param> /// <returns>The message that can be used to write the request operation.</returns> protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation( string method, Uri uri, string contentId, BatchPayloadUriOption payloadUriOption, IEnumerable<string> dependsOnIds) { // write pending message data (headers, response line) for a previously unclosed message/request this.WritePendingMessageData(true); // create the new request operation ODataBatchOperationRequestMessage operationRequestMessage = BuildOperationRequestMessage( this.RawOutputContext.OutputStream, method, uri, contentId, /*groupId*/null, dependsOnIds, ODataFormat.Batch); this.SetState(BatchWriterState.OperationCreated); // write the operation's start boundary string this.WriteStartBoundaryForOperation(); // write the headers and request line ODataMultipartMixedBatchWriterUtils.WriteRequestPreamble(this.RawOutputContext.TextWriter, method, uri, this.RawOutputContext.MessageWriterSettings.BaseUri, changeSetBoundary != null, contentId, payloadUriOption); return operationRequestMessage; }
private static Stream GetMessageStream(ODataBatchOperationRequestMessage requestMessage, WriterTestConfiguration testConfiguration) { if (testConfiguration.Synchronous) { return requestMessage.GetStream(); } else { var t = requestMessage.GetStreamAsync(); t.Wait(); return t.Result; } }
internal static StorageRequestMessage BuildRequestForTableBatchOperation <T>(RESTCommand <T> cmd, Uri uri, UriQueryBuilder builder, int?timeout, string tableName, TableBatchOperation batch, CloudTableClient client, HttpContent content, OperationContext ctx, TablePayloadFormat payloadFormat, ICanonicalizer canonicalizer, StorageCredentials credentials) { StorageRequestMessage msg = BuildRequestCore(NavigationHelper.AppendPathToSingleUri(uri, "$batch"), builder, HttpMethod.Post, timeout, content, ctx, canonicalizer, credentials); Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat); // create the writer, indent for readability of the examples. ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings() { CheckCharacters = false, // sets this flag on the XmlWriter for ATOM Version = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry }; HttpRequestAdapterMessage adapterMsg = new HttpRequestAdapterMessage(msg, client.BufferManager, 64 * (int)Constants.KB); cmd.StreamToDispose = adapterMsg.GetStream(); // Start Batch ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings); ODataBatchWriter batchWriter = odataWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve; // Query operations should not be inside changeset in payload if (!isQuery) { // Start Operation batchWriter.WriteStartChangeset(); batchWriter.Flush(); } foreach (TableOperation operation in batch) { string httpMethod = operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge ? "MERGE" : operation.HttpMethod.Method; ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(uri, tableName)); SetAcceptAndContentTypeForODataBatchMessage(mimePartMsg, payloadFormat); // etag if (operation.OperationType == TableOperationType.Delete || operation.OperationType == TableOperationType.Replace || operation.OperationType == TableOperationType.Merge) { mimePartMsg.SetHeader("If-Match", operation.Entity.ETag); } // Prefer header if (operation.OperationType == TableOperationType.Insert) { mimePartMsg.SetHeader("Prefer", operation.EchoContent ? "return-content" : "return-no-content"); } if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve) { using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings, new TableStorageModel(client.AccountName))) { // Write entity ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter(); WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter); } } } if (!isQuery) { // End Operation batchWriter.WriteEndChangeset(); } // End Batch batchWriter.WriteEndBatch(); batchWriter.Flush(); return(adapterMsg.GetPopulatedMessage()); }
private byte[] CreateBatchRequest(string batchContentType, int unitRepeatCount) { Debug.Assert(!string.IsNullOrEmpty(batchContentType), "!string.IsNullOrEmpty(batchContentType)"); MemoryStream stream = new MemoryStream(); IODataRequestMessage requestMessage = new InMemoryMessage { Stream = stream }; requestMessage.SetHeader("Content-Type", batchContentType); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.BaseUri = new Uri(serviceDocumentUri); using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings)) { ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); // Each iteration generates a change set with two operations, followed by one top level operation. // Operations count in each iteration is three. // Use API available in OData 7.2 for (int idx = 0; idx < unitRepeatCount * NumOfRequestPerUnit; idx += NumOfRequestPerUnit) { batchWriter.WriteStartChangeset(); ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage( "PUT", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), idx.ToString()); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage)) { ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(); ODataResource entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = "webid_" + idx }, new ODataProperty() { Name = "Name", Value = this.aLongString } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } // A PATCH operation. ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), (idx + 1).ToString(), BatchPayloadUriOption.AbsoluteUri); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = "webid_" + (idx + 1) } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } batchWriter.WriteEndChangeset(); ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage( "GET", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), (idx + 2).ToString()); queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full"); } batchWriter.WriteEndBatch(); stream.Position = 0; return(stream.ToArray()); } }
private byte[] CreateBigBatchRequest(int repeatCount) { MemoryStream stream = new MemoryStream(); IODataRequestMessage requestMessage = new InMemoryMessage { Stream = stream }; requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.BaseUri = new Uri(serviceDocumentUri); using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings)) { ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); // Each iteration generates a change set with two operations, followed by one top level operation. // Operations count in each iteration is three. for (int idx = 0; idx < repeatCount * 3; idx += 3) { batchWriter.WriteStartChangeset(); ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage( "PUT", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), idx.ToString()); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage)) { ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(); ODataResource entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = "webid_" + idx }, new ODataProperty() { Name = "Name", Value = this.aVeryLongString } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } // A PATCH operation that depends on the preceding PUT operation. List <string> dependsOnIds = new List <string> { idx.ToString() }; ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$" + idx)), (idx + 1).ToString(), BatchPayloadUriOption.AbsoluteUri, dependsOnIds); // Verify that input values are copied into a new list. Assert.Equal(dependsOnIds, updateOperationMessage.DependsOnIds); Assert.NotSame(dependsOnIds, updateOperationMessage.DependsOnIds); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = "webid_" + (idx + 1) } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId); batchWriter.WriteEndChangeset(); ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage( "GET", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), (idx + 2).ToString()); queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full"); } batchWriter.WriteEndBatch(); stream.Position = 0; return(stream.ToArray()); } }
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); } }
internal static HttpRequestMessage BuildRequestForTableBatchOperation(Uri uri, int?timeout, Uri baseUri, string tableName, TableBatchOperation batch, OperationContext ctx) { HttpRequestMessage msg = BuildRequestCore(NavigationHelper.AppendPathToUri(uri, "$batch"), HttpMethod.Post, timeout, ctx); // create the writer, indent for readability of the examples. ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings() { CheckCharacters = false, // sets this flag on the XmlWriter for ATOM Version = ODataVersion.V2 // set the Odata version to use when writing the entry }; HttpRequestAdapterMessage adapterMsg = new HttpRequestAdapterMessage(msg); // Start Batch ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings); ODataBatchWriter batchWriter = odataWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve; // Query operations should not be inside changeset in payload if (!isQuery) { // Start Operation batchWriter.WriteStartChangeset(); batchWriter.Flush(); } foreach (TableOperation operation in batch) { string httpMethod = operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge ? "MERGE" : operation.HttpMethod.Method; ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(baseUri, tableName)); // etag if (operation.OperationType == TableOperationType.Delete || operation.OperationType == TableOperationType.Replace || operation.OperationType == TableOperationType.Merge) { mimePartMsg.SetHeader("If-Match", operation.Entity.ETag); } if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve) { using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings)) { // Write entity ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter(); WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter); } } } if (!isQuery) { // End Operation batchWriter.WriteEndChangeset(); } // End Batch batchWriter.WriteEndBatch(); batchWriter.Flush(); return(adapterMsg.GetPopulatedMessage()); }
private byte[] ServiceReadBatchRequestAndWriterBatchResponse(byte[] requestPayload, BodyContentType bodyContentType) { IODataRequestMessage requestMessage = new InMemoryMessage() { Stream = new MemoryStream(requestPayload) }; requestMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson); using (ODataMessageReader messageReader = new ODataMessageReader(requestMessage, new ODataMessageReaderSettings(), null)) { MemoryStream responseStream = new MemoryStream(); IODataResponseMessage responseMessage = new InMemoryMessage { Stream = responseStream }; // Client is expected to receive the response message in the same format as that is used in the request sent. responseMessage.SetHeader(ODataConstants.ContentTypeHeader, batchContentTypeApplicationJson); ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage); ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); ODataBatchReader batchReader = messageReader.CreateODataBatchReader(); while (batchReader.Read()) { switch (batchReader.State) { case ODataBatchReaderState.Operation: ODataBatchOperationRequestMessage operationMessage = batchReader.CreateOperationRequestMessage(); if (operationMessage.Method == "PUT") { using (Stream operationMessageBodyStream = operationMessage.GetStream()) { // Verify the bytes in the request operation stream. byte[] sampleBytes = bodyContentType == BodyContentType.Textual ? Encoding.UTF8.GetBytes("\"" + this.textualSampleStringA + "\"") : binarySampleBytesA; Assert.Equal(operationMessageBodyStream.Length, sampleBytes.Length); foreach (byte samplebyte in sampleBytes) { Assert.Equal(samplebyte, operationMessageBodyStream.ReadByte()); } } // Create the response. ODataBatchOperationResponseMessage operationResponse = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId); operationResponse.StatusCode = 201; operationResponse.SetHeader("CoNtEnT-TyPe", "application/json;odata.metadata=none"); } else if (operationMessage.Method == "GET") { ODataBatchOperationResponseMessage operationResponse = batchWriter.CreateOperationResponseMessage(operationMessage.ContentId); operationResponse.StatusCode = 200; operationResponse.SetHeader("CoNtEnT-TyPe", GetContentType(bodyContentType)); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.SetServiceDocumentUri(new Uri(serviceDocumentUri)); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(operationResponse, settings, null)) { operationMessageWriter.WriteValue(GetEncodedContentObject(bodyContentType, false)); } } break; case ODataBatchReaderState.ChangesetStart: batchWriter.WriteStartChangeset(); break; case ODataBatchReaderState.ChangesetEnd: batchWriter.WriteEndChangeset(); break; } } batchWriter.WriteEndBatch(); responseStream.Position = 0; return(responseStream.ToArray()); } }
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); } }
/// <summary> /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation /// in a batch request. /// </summary> /// <returns>The message that can be used to read the content of the batch request operation from.</returns> protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation() { Debug.Assert(this.mode == ReaderMode.Requests, "this.mode == ReaderMode.Requests"); Debug.Assert(this.messagePropertiesCache != null, "this.messagePropertiesCache != null"); // id string id = (string)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameId); // atomicityGroup string atomicityGroupId = (string)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameAtomicityGroup); if (id != null) { this.requestIds.Add(id); } if (atomicityGroupId != null) { this.requestIds.Add(atomicityGroupId); } // dependsOn // Flatten the dependsOn list by converting every groupId into request Ids, so that the caller // can decide, at the earliest opportunity, whether the depending request can be invoked. // Note that the forward reference of dependsOn id is not allowed, so the atomicGroups should have accurate // information of atomicGroup that needs to be flattened. IList <string> dependsOnReqIds = null; List <string> dependsOn = (List <string>) this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameDependsOn); if (dependsOn != null && dependsOn.Count != 0) { ValidateDependsOnId(dependsOn, atomicityGroupId, id); dependsOnReqIds = atomicGroups.GetFlattenedMessageIds(dependsOn); } // header ODataBatchOperationHeaders headers = (ODataBatchOperationHeaders)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameHeaders); // Add the atomicityGroup request header. if (atomicityGroupId != null) { headers.Add(ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameAtomicityGroup, atomicityGroupId); } // body. Use empty stream when request body is not present. Stream bodyContentStream = (Stream)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameBody) ?? new ODataJsonLightBatchBodyContentReaderStream(this); // method. Support case-insensitive value of HTTP methods. string httpMethod = (string)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameMethod); ValidateRequiredProperty(httpMethod, ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameMethod); httpMethod = httpMethod.ToUpperInvariant(); // url string url = (string)this.messagePropertiesCache.GetPropertyValue( ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameUrl); ValidateRequiredProperty(url, ODataJsonLightBatchPayloadItemPropertiesCache.PropertyNameUrl); // escape any colons in the query string portion of the url int queryOptionSeparator = url.IndexOf('?'); int firstColon = url.IndexOf(':'); if (queryOptionSeparator > 0 && firstColon > 0 && queryOptionSeparator < firstColon) { url = url.Substring(0, queryOptionSeparator) + url.Substring(queryOptionSeparator).Replace(":", "%3A"); } Uri requestUri = new Uri(url, UriKind.RelativeOrAbsolute); // Reset the request property cache since all data in cache has been processed. // So that new instance can be created during subsequent read in operation state. this.messagePropertiesCache = null; ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage( () => bodyContentStream, httpMethod, requestUri, headers, id, atomicityGroupId, dependsOnReqIds, /*dependsOnIdsValidationRequired*/ true); return(requestMessage); }
/// <summary> /// Create a batch request that contains one atomic groups. /// </summary> /// <param name="atomicGroupIdFromRequest">Output string for the atomic group id from the batch created.</param> /// <returns>Stream containing the batch request.</returns> private byte[] CreateBatchRequestWithAtomicGroup(out string atomicGroupIdFromRequest) { MemoryStream stream = new MemoryStream(); IODataRequestMessage requestMessage = new InMemoryMessage { Stream = stream }; requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.BaseUri = new Uri(serviceDocumentUri); using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings)) { ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); batchWriter.WriteStartChangeset(); // Create operation. ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage( "PUT", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), "1"); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage)) { ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(); ODataResource entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 10 }, new ODataProperty() { Name = "Name", Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest" } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } // A PATCH operation that depends on the preceding PUT operation. List <string> dependsOnIds = new List <string> { "1" }; ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1")), "2", BatchPayloadUriOption.AbsoluteUri, dependsOnIds); // Verify that input values are copied into a new list. Assert.Equal(dependsOnIds, updateOperationMessage.DependsOnIds); Assert.NotSame(dependsOnIds, updateOperationMessage.DependsOnIds); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 11 } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId); batchWriter.WriteEndChangeset(); ODataBatchOperationRequestMessage update2OperationMessage = batchWriter.CreateOperationRequestMessage( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), "3", BatchPayloadUriOption.AbsoluteUri); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(update2OperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 12 } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } batchWriter.WriteEndBatch(); atomicGroupIdFromRequest = createOperationMessage.GroupId; stream.Position = 0; return(stream.ToArray()); } }
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); } }
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(); } }
internal static Tuple <HttpWebRequest, Stream> BuildRequestForTableBatchOperation(Uri uri, UriQueryBuilder builder, IBufferManager bufferManager, int?timeout, string tableName, TableBatchOperation batch, bool useVersionHeader, OperationContext ctx, TableRequestOptions options, string accountName) { HttpWebRequest msg = BuildRequestCore(NavigationHelper.AppendPathToSingleUri(uri, "$batch"), builder, "POST", timeout, useVersionHeader, ctx); TablePayloadFormat payloadFormat = options.PayloadFormat.Value; Logger.LogInformational(ctx, SR.PayloadFormat, payloadFormat); // create the writer, indent for readability of the examples. ODataMessageWriterSettings writerSettings = new ODataMessageWriterSettings() { CheckCharacters = false, // sets this flag on the XmlWriter for ATOM Version = TableConstants.ODataProtocolVersion // set the Odata version to use when writing the entry }; HttpWebRequestAdapterMessage adapterMsg = new HttpWebRequestAdapterMessage(msg, bufferManager); // Start Batch ODataMessageWriter odataWriter = new ODataMessageWriter(adapterMsg, writerSettings); ODataBatchWriter batchWriter = odataWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); bool isQuery = batch.Count == 1 && batch[0].OperationType == TableOperationType.Retrieve; // Query operations should not be inside changeset in payload if (!isQuery) { // Start Operation batchWriter.WriteStartChangeset(); batchWriter.Flush(); } foreach (TableOperation operation in batch) { string httpMethod = operation.HttpMethod; if (operation.OperationType == TableOperationType.Merge || operation.OperationType == TableOperationType.InsertOrMerge) { options.AssertNoEncryptionPolicyOrStrictMode(); httpMethod = "MERGE"; } ODataBatchOperationRequestMessage mimePartMsg = batchWriter.CreateOperationRequestMessage(httpMethod, operation.GenerateRequestURI(uri, tableName)); SetAcceptAndContentTypeForODataBatchMessage(mimePartMsg, payloadFormat); // etag if (operation.OperationType == TableOperationType.Delete || operation.OperationType == TableOperationType.Replace || operation.OperationType == TableOperationType.Merge) { mimePartMsg.SetHeader("If-Match", operation.Entity.ETag); } // Prefer header if (operation.OperationType == TableOperationType.Insert) { mimePartMsg.SetHeader("Prefer", operation.EchoContent ? "return-content" : "return-no-content"); } if (operation.OperationType != TableOperationType.Delete && operation.OperationType != TableOperationType.Retrieve) { using (ODataMessageWriter batchEntryWriter = new ODataMessageWriter(mimePartMsg, writerSettings, new TableStorageModel(accountName))) { // Write entity ODataWriter entryWriter = batchEntryWriter.CreateODataEntryWriter(); WriteOdataEntity(operation.Entity, operation.OperationType, ctx, entryWriter, options); } } } if (!isQuery) { // End Operation batchWriter.WriteEndChangeset(); } // End Batch batchWriter.WriteEndBatch(); batchWriter.Flush(); return(new Tuple <HttpWebRequest, Stream>(adapterMsg.GetPopulatedMessage(), adapterMsg.GetStream())); }
/// <summary> /// Create a batch request that contains atomic groups. /// </summary> /// <param name="atomicGroupIdFromRequest">Output string for the first atomic group id from the batch created.</param> /// <param name="atomicGroupAIdFromRequest">Output string for the second atomic group id from the batch created.</param> /// <returns>Stream containing the batch request.</returns> private byte[] CreateBatchRequestWithMultipleAtomicGroups( out string atomicGroupIdFromRequest, out string atomicGroupAIdFromRequest) { MemoryStream stream = new MemoryStream(); IODataRequestMessage requestMessage = new InMemoryMessage { Stream = stream }; requestMessage.SetHeader("Content-Type", batchContentTypeApplicationJson); ODataMessageWriterSettings settings = new ODataMessageWriterSettings(); settings.BaseUri = new Uri(serviceDocumentUri); using (ODataMessageWriter messageWriter = new ODataMessageWriter(requestMessage, settings)) { ODataBatchWriter batchWriter = messageWriter.CreateODataBatchWriter(); batchWriter.WriteStartBatch(); // Lexical scope for first half: query ("3"), create("1"), patch("2") { // Query operation ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage("GET", new Uri(serviceDocumentUri + "MySingleton"), "3"); queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full"); batchWriter.WriteStartChangeset(); // Create operation. ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage ( "PUT", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), "1"); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage)) { ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(); ODataResource entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 10 }, new ODataProperty() { Name = "Name", Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest" } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } // A PATCH operation that depends on the preceding PUT operation. string[] dependsOnIds = new string[] { "1" }; ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage ( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1")), "2", BatchPayloadUriOption.AbsoluteUri, dependsOnIds); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 11 } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId); batchWriter.WriteEndChangeset(); atomicGroupIdFromRequest = createOperationMessage.GroupId; } // Lexical scope for second half: create("1A"), patch("2A"), query("3A") { batchWriter.WriteStartChangeset(); // Create operation. ODataBatchOperationRequestMessage createOperationMessage = batchWriter.CreateOperationRequestMessage ( "PUT", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "MySingleton")), "1A"); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(createOperationMessage)) { ODataWriter entryWriter = operationMessageWriter.CreateODataResourceWriter(); ODataResource entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 10 }, new ODataProperty() { Name = "Name", Value = "SingletonWebForBatchJsonLightAtomicGroupIdTest" } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } // A PATCH operation that depends on the preceding PUT operation. string[] dependsOnIds = new string[] { "1A" }; ODataBatchOperationRequestMessage updateOperationMessage = batchWriter.CreateOperationRequestMessage ( "PATCH", new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/{1}", serviceDocumentUri, "$1A")), "2A", BatchPayloadUriOption.AbsoluteUri, dependsOnIds); using (ODataMessageWriter operationMessageWriter = new ODataMessageWriter(updateOperationMessage)) { var entryWriter = operationMessageWriter.CreateODataResourceWriter(); var entry = new ODataResource() { TypeName = "NS.Web", Properties = new[] { new ODataProperty() { Name = "WebId", Value = 11 } } }; entryWriter.WriteStart(entry); entryWriter.WriteEnd(); } Assert.Equal(createOperationMessage.GroupId, updateOperationMessage.GroupId); batchWriter.WriteEndChangeset(); atomicGroupAIdFromRequest = createOperationMessage.GroupId; // Query operation ODataBatchOperationRequestMessage queryOperationMessage = batchWriter.CreateOperationRequestMessage("GET", new Uri(serviceDocumentUri + "MySingleton"), "3A"); queryOperationMessage.SetHeader("Accept", "application/json;odata.metadata=full"); } batchWriter.WriteEndBatch(); Assert.NotEqual(atomicGroupIdFromRequest, atomicGroupAIdFromRequest); stream.Position = 0; return(stream.ToArray()); } }