Ejemplo n.º 1
0
        internal static async Task <IList <TableResult> > TableBatchOperationPostProcess(IList <TableResult> result, TableBatchOperation batch, RESTCommand <IList <TableResult> > cmd, HttpResponseMessage resp, OperationContext ctx, TableRequestOptions options, CancellationToken cancellationToken)
        {
            Stream       responseStream = cmd.ResponseStream;
            StreamReader streamReader   = new StreamReader(responseStream);
            string       currentLine    = await streamReader.ReadLineAsync().ConfigureAwait(false);

            currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);

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

            while ((currentLine != null) && !(currentLine.StartsWith(@"--batchresponse")))
            //while (reader.State == ODataBatchReaderState.Operation)
            {
                while (!(currentLine.StartsWith("HTTP")))
                {
                    currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);
                }

                // The first line of the response looks like this:
                // HTTP/1.1 204 No Content
                // The HTTP status code is chars 9 - 11.
                int statusCode = Int32.Parse(currentLine.Substring(9, 3));

                Dictionary <string, string> headers = new Dictionary <string, string>();
                currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);

                while (!string.IsNullOrWhiteSpace(currentLine))
                {
                    // The headers all look like this:
                    // Cache-Control: no-cache
                    // This code below parses out the header names and values, by noting the location of the colon.
                    int colonIndex = currentLine.IndexOf(':');
                    headers[currentLine.Substring(0, colonIndex)] = currentLine.Substring(colonIndex + 2);
                    currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);
                }

                MemoryStream bodyStream = null;

                currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);

                if (statusCode != 204)
                {
                    bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(currentLine));
                }

                currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);

                currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);

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

                string contentType = null;

                if (headers.ContainsKey(Constants.ContentTypeElement))
                {
                    contentType = headers[Constants.ContentTypeElement];
                }

                currentResult.HttpStatusCode = statusCode;

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

                    failUnexpected = statusCode != (int)HttpStatusCode.OK;
                }
                else
                {
                    failError      = statusCode == (int)HttpStatusCode.NotFound;
                    failUnexpected = 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(bodyStream, resp, contentType);
                    }
                    else
                    {
                        cmd.CurrentResult.ExtendedErrorInformation = StorageExtendedErrorInformation.ReadFromStream(bodyStream);
                    }

                    cmd.CurrentResult.HttpStatusCode = statusCode;
                    if (!string.IsNullOrEmpty(cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage))
                    {
                        string msg = cmd.CurrentResult.ExtendedErrorInformation.ErrorMessage;
                        cmd.CurrentResult.HttpStatusMessage = msg.Substring(0, msg.IndexOf("\n"));
                    }
                    else
                    {
                        cmd.CurrentResult.HttpStatusMessage = statusCode.ToString();
                    }

                    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(bodyStream, resp, contentType);
                    }

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

                    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, string.Format(SR.BatchErrorInOperation, indexString), null)
                          {
                              IsRetryable = true
                          };
                }

                if ((headers.ContainsKey(Constants.HeaderConstants.EtagHeader)) && (!string.IsNullOrEmpty(headers[Constants.HeaderConstants.EtagHeader])))
                {
                    currentResult.Etag = headers[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 (headers[Constants.ContentTypeElement].Contains(Constants.JsonNoMetadataAcceptHeaderValue))
                    {
                        await ReadEntityUsingJsonParserAsync(currentResult, currentOperation, bodyStream, ctx, options, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        await ReadOdataEntityAsync(currentResult, currentOperation, bodyStream, ctx, options, cancellationToken).ConfigureAwait(false);
                    }
                }
                else if (currentOperation.OperationType == TableOperationType.Insert)
                {
                    currentOperation.Entity.Timestamp = ParseETagForTimestamp(currentResult.Etag);
                }

                index++;
            }

            return(result);
        }
Ejemplo n.º 2
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);
        }
        internal static Task <IList <TableResult> > TableBatchOperationPostProcess(IList <TableResult> result, TableBatchOperation batch, RESTCommand <IList <TableResult> > cmd, HttpResponseMessage resp, OperationContext ctx, TableRequestOptions options, string accountName)
        {
            return(Task.Run(() =>
            {
                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);
                            }
                            else
                            {
                                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)
                        {
                            // 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;

                            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, string.Format(SR.BatchErrorInOperation, 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 && currentOperation.EchoContent))
                        {
                            if (mimePartResponseMessage.GetHeader(Constants.ContentTypeElement).Contains(Constants.JsonContentTypeHeaderValue) &&
                                mimePartResponseMessage.GetHeader(Constants.ContentTypeElement).Contains(Constants.NoMetadata))
                            {
                                ReadEntityUsingJsonParser(currentResult, currentOperation, mimePartResponseMessage.GetStream(), ctx, options);
                            }
                            else
                            {
                                ReadOdataEntity(currentResult, currentOperation, mimePartResponseMessage, ctx, readerSettings, accountName);
                            }
                        }
                        else if (currentOperation.OperationType == TableOperationType.Insert)
                        {
                            currentOperation.Entity.Timestamp = ParseETagForTimestamp(currentResult.Etag);
                        }

                        index++;

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

                return result;
            }));
        }