Пример #1
0
        public async Task <Lease> CreateLeaseIfNotExistsAsync(string partitionId) // throws URISyntaxException, IOException, StorageException
        {
            AzureBlobLease returnLease;

            try
            {
                CloudBlockBlob leaseBlob = this.consumerGroupDirectory.GetBlockBlobReference(partitionId);
                returnLease = new AzureBlobLease(partitionId, leaseBlob);
                string jsonLease = JsonConvert.SerializeObject(returnLease);

                ProcessorEventSource.Log.AzureStorageManagerInfo(
                    this.host.Id,
                    partitionId,
                    "CreateLeaseIfNotExist - leaseContainerName: " + this.leaseContainerName + " consumerGroupName: " + this.host.ConsumerGroupName);
                await leaseBlob.UploadTextAsync(jsonLease, null, AccessCondition.GenerateIfNoneMatchCondition("*"), null, null);
            }
            catch (StorageException se)
            {
                StorageExtendedErrorInformation extendedErrorInfo = se.RequestInformation.ExtendedErrorInformation;
                if (extendedErrorInfo != null &&
                    (extendedErrorInfo.ErrorCode == BlobErrorCodeStrings.BlobAlreadyExists ||
                     extendedErrorInfo.ErrorCode == BlobErrorCodeStrings.LeaseIdMissing)) // occurs when somebody else already has leased the blob
                {
                    // The blob already exists.
                    ProcessorEventSource.Log.AzureStorageManagerInfo(this.host.Id, partitionId, "Lease already exists");
                    returnLease = (AzureBlobLease)(await GetLeaseAsync(partitionId));
                }
                else
                {
                    Console.WriteLine("errorCode " + extendedErrorInfo.ErrorCode);
                    Console.WriteLine("errorString " + extendedErrorInfo.ErrorMessage);

                    ProcessorEventSource.Log.AzureStorageManagerError(
                        this.host.Id,
                        partitionId,
                        "CreateLeaseIfNotExist StorageException - leaseContainerName: " + this.leaseContainerName + " consumerGroupName: " + this.host.ConsumerGroupName,
                        se.ToString());
                    throw;
                }
            }

            return(returnLease);
        }
Пример #2
0
        /// <summary>
        /// Deletes the table if it already exists.
        /// </summary>
        /// <param name="requestOptions">A <see cref="TableRequestOptions"/> object that specifies execution options, such as retry policy and timeout settings, for the operation.</param>
        /// <param name="operationContext">An <see cref="OperationContext"/> object for tracking the current operation.</param>
        /// <returns><c>true</c> if the table already existed and was deleted; otherwise, <c>false</c>.</returns>
        public IAsyncOperation <bool> DeleteIfExistsAsync(TableRequestOptions requestOptions, OperationContext operationContext)
        {
            requestOptions = TableRequestOptions.ApplyDefaults(requestOptions, this.ServiceClient);

            operationContext = operationContext ?? new OperationContext();

            return(AsyncInfo.Run(async(cancellationToken) =>
            {
                if (!await this.ExistsAsync(requestOptions, operationContext).AsTask(cancellationToken))
                {
                    return false;
                }
                else
                {
                    try
                    {
                        await this.DeleteAsync(requestOptions, operationContext).AsTask(cancellationToken);
                        return true;
                    }
                    catch (Exception)
                    {
                        if (operationContext.LastResult.HttpStatusCode == (int)HttpStatusCode.NotFound)
                        {
                            StorageExtendedErrorInformation extendedInfo = operationContext.LastResult.ExtendedErrorInformation;
                            if ((extendedInfo == null) ||
                                (extendedInfo.ErrorCode == TableErrorCodeStrings.TableNotFound))
                            {
                                return false;
                            }
                            else
                            {
                                throw;
                            }
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }));
        }
Пример #3
0
        public IAsyncOperation <bool> CreateIfNotExistsAsync(FileRequestOptions options, OperationContext operationContext)
        {
            FileRequestOptions modifiedOptions = FileRequestOptions.ApplyDefaults(options, this.ServiceClient);

            operationContext = operationContext ?? new OperationContext();

            return(AsyncInfo.Run(async(token) =>
            {
                bool exists = await this.ExistsAsync(modifiedOptions, operationContext).AsTask(token);

                if (exists)
                {
                    return false;
                }

                try
                {
                    await this.CreateAsync(modifiedOptions, operationContext).AsTask(token);
                    return true;
                }
                catch (Exception)
                {
                    if (operationContext.LastResult.HttpStatusCode == (int)HttpStatusCode.Conflict)
                    {
                        StorageExtendedErrorInformation extendedInfo = operationContext.LastResult.ExtendedErrorInformation;
                        if ((extendedInfo == null) ||
                            (extendedInfo.ErrorCode == FileErrorCodeStrings.ShareAlreadyExists))
                        {
                            return false;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    else
                    {
                        throw;
                    }
                }
            }));
        }
Пример #4
0
        public virtual Task <bool> DeleteIfExistsAsync(AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext, CancellationToken cancellationToken)
        {
            FileRequestOptions modifiedOptions = FileRequestOptions.ApplyDefaults(options, this.ServiceClient);

            operationContext = operationContext ?? new OperationContext();

            return(Task.Run(async() =>
            {
                bool exists = await this.ExistsAsync(modifiedOptions, operationContext, cancellationToken);

                if (!exists)
                {
                    return false;
                }

                try
                {
                    await this.DeleteAsync(accessCondition, modifiedOptions, operationContext, cancellationToken);
                    return true;
                }
                catch (Exception)
                {
                    if (operationContext.LastResult.HttpStatusCode == (int)HttpStatusCode.NotFound)
                    {
                        StorageExtendedErrorInformation extendedInfo = operationContext.LastResult.ExtendedErrorInformation;
                        if ((extendedInfo == null) ||
                            (extendedInfo.ErrorCode == FileErrorCodeStrings.ShareNotFound))
                        {
                            return false;
                        }
                        else
                        {
                            throw;
                        }
                    }
                    else
                    {
                        throw;
                    }
                }
            }, cancellationToken));
        }
Пример #5
0
        /// <summary>
        /// Starts an asynchronous AppendBlock operation as soon as the parallel
        /// operation semaphore becomes available. Since parallelism is always set
        /// to 1 for append blobs, appendblock operations are called serially.
        /// </summary>
        /// <param name="blockData">Data to be uploaded</param>
        /// <param name="offset">Offset within the append blob to be used to set the append offset conditional header.</param>
        /// <param name="blockMD5">MD5 hash of the data to be uploaded</param>
        /// <returns>A task that represents the asynchronous write operation.</returns>
        private async Task WriteAppendBlockAsync(Stream blockData, long offset, string blockMD5)
        {
            this.noPendingWritesEvent.Increment();
            await this.parallelOperationSemaphore.WaitAsync().ConfigureAwait(false);

            this.accessCondition.IfAppendPositionEqual = offset;

            int  previousResultsCount = this.operationContext.RequestResults.Count;
            Task writeBlockTask       = this.appendBlob.AppendBlockAsync(blockData, blockMD5, this.accessCondition, this.options, this.operationContext).ContinueWith(task =>
            {
                if (task.Exception != null)
                {
                    if (this.options.AbsorbConditionalErrorsOnRetry.Value &&
                        this.operationContext.LastResult.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
                    {
                        StorageExtendedErrorInformation extendedInfo = this.operationContext.LastResult.ExtendedErrorInformation;
#pragma warning disable 618
                        if (extendedInfo != null &&
                            (extendedInfo.ErrorCode == BlobErrorCodeStrings.InvalidAppendCondition || extendedInfo.ErrorCode == BlobErrorCodeStrings.InvalidMaxBlobSizeCondition) &&
                            (this.operationContext.RequestResults.Count - previousResultsCount > 1))
#pragma warning restore 618
                        {
                            // Pre-condition failure on a retry should be ignored in a single writer scenario since the request
                            // succeeded in the first attempt.
                            Logger.LogWarning(this.operationContext, SR.PreconditionFailureIgnored);
                        }
                        else
                        {
                            this.lastException = task.Exception;
                        }
                    }
                    else
                    {
                        this.lastException = task.Exception;
                    }
                }

                this.noPendingWritesEvent.Decrement();
                this.parallelOperationSemaphore.Release();
            });
        }
Пример #6
0
        /// <summary>
        /// Returns the error code from storage exception, or null.
        /// </summary>
        /// <param name="exception">The storage exception.</param>
        /// <returns>The error code, or null.</returns>
        public static string GetErrorCode(this StorageException exception)
        {
            if (exception == null)
            {
                throw new ArgumentNullException("exception");
            }

            RequestResult result = exception.RequestInformation;

            if (result == null)
            {
                return(null);
            }

            StorageExtendedErrorInformation extendedInformation = result.ExtendedErrorInformation;

            if (extendedInformation == null)
            {
                return(null);
            }

            return(extendedInformation.ErrorCode);
        }
        private static async Task <StorageExtendedErrorInformation> ReadXmlAsync(XmlReader reader, CancellationToken cancellationToken)
        {
            StorageExtendedErrorInformation extendedErrorInformation = new StorageExtendedErrorInformation();

            CommonUtility.AssertNotNull("reader", reader);
            extendedErrorInformation.AdditionalDetails = new Dictionary <string, string>();
            await reader.ReadStartElementAsync().ConfigureAwait(continueOnCapturedContext: false);

            cancellationToken.ThrowIfCancellationRequested();
            while (await reader.IsStartElementAsync().ConfigureAwait(continueOnCapturedContext: false))
            {
                if (reader.IsEmptyElement)
                {
                    await reader.SkipAsync().ConfigureAwait(continueOnCapturedContext: false);

                    cancellationToken.ThrowIfCancellationRequested();
                }
                else if (string.Compare(reader.LocalName, "Code", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(reader.LocalName, "code", StringComparison.Ordinal) == 0)
                {
                    StorageExtendedErrorInformation storageExtendedErrorInformation = extendedErrorInformation;
                    storageExtendedErrorInformation.ErrorCode = await reader.ReadElementContentAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);

                    cancellationToken.ThrowIfCancellationRequested();
                }
                else if (string.Compare(reader.LocalName, "Message", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(reader.LocalName, "message", StringComparison.Ordinal) == 0)
                {
                    StorageExtendedErrorInformation storageExtendedErrorInformation = extendedErrorInformation;
                    storageExtendedErrorInformation.ErrorMessage = await reader.ReadElementContentAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);

                    cancellationToken.ThrowIfCancellationRequested();
                }
                else if (string.Compare(reader.LocalName, "exceptiondetails", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    await reader.ReadStartElementAsync(null, null).ConfigureAwait(continueOnCapturedContext: false);

                    cancellationToken.ThrowIfCancellationRequested();
                    while (await reader.IsStartElementAsync().ConfigureAwait(continueOnCapturedContext: false))
                    {
                        string localName = reader.LocalName;
                        if (!(localName == "ExceptionMessage"))
                        {
                            if (localName == "StackTrace")
                            {
                                IDictionary <string, string> additionalDetails = extendedErrorInformation.AdditionalDetails;
                                additionalDetails.Add("StackTrace", await reader.ReadElementContentAsStringAsync("StackTrace", string.Empty).ConfigureAwait(continueOnCapturedContext: false));
                                cancellationToken.ThrowIfCancellationRequested();
                            }
                            else
                            {
                                await reader.SkipAsync().ConfigureAwait(continueOnCapturedContext: false);

                                cancellationToken.ThrowIfCancellationRequested();
                            }
                        }
                        else
                        {
                            IDictionary <string, string> additionalDetails = extendedErrorInformation.AdditionalDetails;
                            additionalDetails.Add("ExceptionMessage", await reader.ReadElementContentAsStringAsync("ExceptionMessage", string.Empty).ConfigureAwait(continueOnCapturedContext: false));
                            cancellationToken.ThrowIfCancellationRequested();
                        }
                    }
                    await reader.ReadEndElementAsync().ConfigureAwait(continueOnCapturedContext: false);

                    cancellationToken.ThrowIfCancellationRequested();
                }
                else
                {
                    IDictionary <string, string> additionalDetails = extendedErrorInformation.AdditionalDetails;
                    string localName2 = reader.LocalName;
                    additionalDetails.Add(localName2, await reader.ReadInnerXmlAsync().ConfigureAwait(continueOnCapturedContext: false));
                    cancellationToken.ThrowIfCancellationRequested();
                }
            }
            await reader.ReadEndElementAsync().ConfigureAwait(continueOnCapturedContext: false);

            cancellationToken.ThrowIfCancellationRequested();
            return(extendedErrorInformation);
        }
Пример #8
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);
        }
Пример #9
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);
        }
Пример #10
0
 internal static Exception UnableToParseTextBeforeSemicolonToInteger(StorageExtendedErrorInformation error)
 {
     return(new UnexpectedStorageResponseException(error, "Unable to parse text on first line before semicolon as integer"));
 }
Пример #11
0
 internal static Exception ConflictExceptionMessageShouldHaveSemicolonOnFirstLine(StorageExtendedErrorInformation error)
 {
     return(new UnexpectedStorageResponseException(error, "Conflict exception message should have semicolon on first line"));
 }
Пример #12
0
 internal static Exception ConflictExceptionMessageShouldHaveExactlyThreeLines(StorageExtendedErrorInformation error)
 {
     return(new UnexpectedStorageResponseException(error, "Conflict exception message should have exactly 3 lines"));
 }
Пример #13
0
 internal static Exception ErrorCodeShouldBeEntityAlreadyExists(StorageExtendedErrorInformation error)
 {
     return(new UnexpectedStorageResponseException(error, "Erorr code should be indicated as 'EntityAlreadyExists' but was: " + error.ErrorCode));
 }
Пример #14
0
 UnexpectedStorageResponseException(StorageExtendedErrorInformation error, string details)
     : base("Unexpected Table Storage response. Details: " + details)
 {
     Error = error;
 }
        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;
            }));
        }
Пример #16
0
        internal static async Task <IList <BlobBatchSubOperationResponse> > BatchPostProcessAsync(IList <BlobBatchSubOperationResponse> result, RESTCommand <IList <BlobBatchSubOperationResponse> > cmd, IList <HttpStatusCode> successfulStatusCodes, HttpResponseMessage response, OperationContext ctx, /*BlobRequestOptions options,*/ CancellationToken cancellationToken)
        {
            // TODO reimplement to use ASP.NET extensions to parse multipart content from content stream

            Stream       responseStream = cmd.ResponseStream;
            StreamReader streamReader   = new StreamReader(responseStream);

            List <BlobBatchSubOperationError> errors = new List <BlobBatchSubOperationError>();

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

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

            while ((currentLine != null) && !(currentLine.StartsWith(@"--batchresponse") && currentLine.EndsWith("--")))
            {
                while ((currentLine != null) && !currentLine.StartsWith("Content-ID"))
                {
                    currentLine = await streamReader.ReadLineAsync().ConfigureAwait(false);
                }
                int operationIndex = int.Parse(currentLine.Split(':')[1]);

                while ((currentLine != null) && !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.
                var statusCode = (HttpStatusCode)int.Parse(currentLine.Substring(9, 3));

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

                if (successfulStatusCodes.Contains(statusCode))
                {
                    BlobBatchSubOperationResponse subResponse = new BlobBatchSubOperationResponse
                    {
                        StatusCode     = statusCode,
                        OperationIndex = operationIndex,
                        Headers        = await ParseSubRequestHeadersAsync(currentLine, streamReader).ConfigureAwait(false)
                    };

                    // Can add logic to parse body here if necessary.

                    result.Add(subResponse);
                }
                else
                {
                    // ProcessExpectedStatusCodesNoException? How to share list of expected codes to avoid duplication? Change list type to HttpStatusCode.
                    BlobBatchSubOperationError error = new BlobBatchSubOperationError
                    {
                        OperationIndex = operationIndex,
                        StatusCode     = statusCode
                    };
                    Dictionary <string, string> headers = await ParseSubRequestHeadersAsync(currentLine, streamReader).ConfigureAwait(false);

                    error.ErrorCode = headers[Constants.HeaderConstants.StorageErrorCodeHeader];
                    int contentLength = int.Parse(headers[Constants.HeaderConstants.ContentLengthHeader]);

                    //TODO: Add check that contentLength > 0 in case we support HEAD operations.

                    char[] errorInfoBuffer = new char[contentLength];
                    var    position        = 0;

                    while (position < contentLength)
                    {
                        errorInfoBuffer[position++] = (char)streamReader.Read();
                    }

                    error.ExtendedErrorInformation = await StorageExtendedErrorInformation.ReadFromStreamAsync(new MemoryStream(Encoding.UTF8.GetBytes(errorInfoBuffer))).ConfigureAwait(false); // Is this safe/performant?

                    errors.Add(error);
                }

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

            if (errors.Count > 0)
            {
                BlobBatchException ex = new BlobBatchException
                {
                    ErrorResponses      = errors,
                    SuccessfulResponses = result
                };
                throw ex;
            }
            return(result);
        }