Пример #1
0
        /// <summary>
        /// Deletes the specified blob.
        /// </summary>
        /// <param name="containerName">The target blob container name from which the blob will be deleted.</param>
        /// <param name="blobName">The custom name associated with the blob.</param>
        /// <returns>True if the blob was deleted, otherwise false.</returns>
        public bool Delete(string containerName, string blobName)
        {
            Guard.ArgumentNotNullOrEmptyString(containerName, "containerName");
            Guard.ArgumentNotNullOrEmptyString(blobName, "blobName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(containerName, blobName);

            try
            {
                var container = this.blobStorage.GetContainerReference(CloudUtility.GetSafeContainerName(containerName));
                var cloudBlob = container.GetBlobReference(blobName);

                return(this.retryPolicy.ExecuteAction <bool>(() =>
                {
                    return cloudBlob.DeleteIfExists();
                }));
            }
            catch (StorageClientException ex)
            {
                // If blob doesn't exist, do not re-throw the exception, simply return a null reference.
                if (!(ex.ErrorCode == StorageErrorCode.ContainerNotFound || ex.ErrorCode == StorageErrorCode.BlobNotFound || ex.ErrorCode == StorageErrorCode.ResourceNotFound))
                {
                    throw;
                }
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }

            return(false);
        }
Пример #2
0
        /// <summary>
        /// Gets the approximate number of items in the specified queue.
        /// </summary>
        /// <param name="queueName">The name of the queue to be queried.</param>
        /// <returns>The approximate number of items in the queue.</returns>
        public int GetCount(string queueName)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");

            var callToken    = TraceManager.CloudStorageComponent.TraceIn(queueName);
            int messageCount = 0;

            try
            {
                var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

                messageCount = this.retryPolicy.ExecuteAction <int>(() =>
                {
                    return(queue.RetrieveApproximateMessageCount());
                });

                return(messageCount);
            }
            catch (StorageClientException ex)
            {
                if (ex.ErrorCode == StorageErrorCode.ResourceNotFound || ex.ExtendedErrorInformation.ErrorCode == QueueErrorCodeStrings.QueueNotFound)
                {
                    return(0);
                }

                throw;
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken, messageCount);
            }
        }
Пример #3
0
        /// <summary>
        /// Deletes the specified blob container.
        /// </summary>
        /// <param name="containerName">The name of the blob container to be deleted.</param>
        /// <returns>True if the container existed and was successfully deleted; otherwise false.</returns>
        public bool DeleteContainer(string containerName)
        {
            Guard.ArgumentNotNullOrEmptyString(containerName, "containerName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(containerName);

            try
            {
                var container = this.blobStorage.GetContainerReference(CloudUtility.GetSafeContainerName(containerName));

                return(this.retryPolicy.ExecuteAction <bool>(() =>
                {
                    container.Delete();
                    return true;
                }));
            }
            catch (StorageClientException ex)
            {
                if (ex.ErrorCode == StorageErrorCode.ContainerNotFound || ex.ErrorCode == StorageErrorCode.ResourceNotFound)
                {
                    return(false);
                }

                throw;
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }
        }
Пример #4
0
        /// <summary>
        /// Deletes the specified queue.
        /// </summary>
        /// <param name="queueName">The name of the queue to be deleted.</param>
        /// <returns>True if the queue name has been actually deleted, otherwise False.</returns>
        public bool DeleteQueue(string queueName)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(queueName);

            try
            {
                // Must delete the associated blob storage in which large messages are persisted.
                LargeQueueMessageInfo largeMsgInfo = LargeQueueMessageInfo.Create(queueName);
                this.overflowStorage.DeleteContainer(largeMsgInfo.ContainerName);

                // Now proceed with deleting the queue.
                var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

                return(this.retryPolicy.ExecuteAction <bool>(() =>
                {
                    if (queue.Exists())
                    {
                        queue.Delete();
                        return true;
                    }
                    return false;
                }));
            }
            catch (Exception ex)
            {
                TraceManager.CloudStorageComponent.TraceError(ex);
                return(false);
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }
        }
Пример #5
0
        /// <summary>
        /// Creates a new queue.
        /// </summary>
        /// <param name="queueName">The name of a new queue.</param>
        /// <returns>A flag indicating whether or the queue did not exist and was therefore created.</returns>
        public bool CreateQueue(string queueName)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(queueName);

            try
            {
                var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

                return(this.retryPolicy.ExecuteAction <bool>(() =>
                {
                    return queue.CreateIfNotExist();
                }));
            }
            catch (StorageClientException ex)
            {
                if (ex.ErrorCode == StorageErrorCode.ContainerAlreadyExists || ex.ErrorCode == StorageErrorCode.ResourceAlreadyExists)
                {
                    return(false);
                }

                throw;
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }
        }
Пример #6
0
        /// <summary>
        /// Puts a single message on a queue.
        /// </summary>
        /// <typeparam name="T">The type of the payload associated with the message.</typeparam>
        /// <param name="queueName">The target queue name on which message will be placed.</param>
        /// <param name="message">The payload to be put into a queue.</param>
        public void Put <T>(string queueName, T message)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");
            Guard.ArgumentNotNull(message, "message");

            // Obtain a reference to the queue by its name. The name will be validated against compliance with storage resource names.
            var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

            CloudQueueMessage queueMessage = null;

            // Allocate a memory buffer into which messages will be serialized prior to being put on a queue.
            using (MemoryStream dataStream = new MemoryStream(Convert.ToInt32(CloudQueueMessage.MaxMessageSize)))
            {
                // Perform serialization of the message data into the target memory buffer.
                this.dataSerializer.Serialize(message, dataStream);

                // Reset the position in the buffer as we will be reading its content from the beginning.
                dataStream.Seek(0, SeekOrigin.Begin);

                // First, determine whether the specified message can be accommodated on a queue.
                if (CloudUtility.IsAllowedQueueMessageSize(dataStream.Length))
                {
                    queueMessage = new CloudQueueMessage(dataStream.ToArray());
                }
                else
                {
                    // Create an instance of a large queue item metadata message.
                    LargeQueueMessageInfo queueMsgInfo = LargeQueueMessageInfo.Create(queueName);

                    // Persist the stream of data that represents a large message into the overflow message store.
                    this.overflowStorage.Put <Stream>(queueMsgInfo.ContainerName, queueMsgInfo.BlobReference, dataStream);

                    // Invoke the Put operation recursively to enqueue the metadata message.
                    Put <LargeQueueMessageInfo>(queueName, queueMsgInfo);
                }
            }

            // Check if a message is available to be put on a queue.
            if (queueMessage != null)
            {
                Put(queue, queueMessage);
            }
        }
Пример #7
0
        /// <summary>
        /// Clears all messages from the specified queue.
        /// </summary>
        /// <param name="queueName">The name of the queue that will be emptied.</param>
        public void Clear(string queueName)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(queueName);

            try
            {
                var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

                this.retryPolicy.ExecuteAction(() =>
                {
                    if (queue.Exists())
                    {
                        queue.Clear();
                    }
                });
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }
        }
Пример #8
0
        /// <summary>
        /// Gets the number of blobs in the specified container.
        /// </summary>
        /// <param name="containerName">The name of the blob container to be queried.</param>
        /// <returns>The number of blobs in the container.</returns>
        public int GetCount(string containerName)
        {
            Guard.ArgumentNotNullOrEmptyString(containerName, "containerName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(containerName);
            int blobCount = 0;

            try
            {
                var container = this.blobStorage.GetContainerReference(CloudUtility.GetSafeContainerName(containerName));

                blobCount = this.retryPolicy.ExecuteAction <int>(() =>
                {
                    var blobList = container.ListBlobs(new BlobRequestOptions()
                    {
                        BlobListingDetails = BlobListingDetails.None, RetryPolicy = RetryPolicies.NoRetry(), UseFlatBlobListing = true
                    });
                    return(blobList != null ? blobList.Count() : 0);
                });

                return(blobCount);
            }
            catch (StorageClientException ex)
            {
                // If blob doesn't exist, do not re-throw the exception, simply return a null reference.
                if (!(ex.ErrorCode == StorageErrorCode.ContainerNotFound || ex.ErrorCode == StorageErrorCode.BlobNotFound || ex.ErrorCode == StorageErrorCode.ResourceNotFound))
                {
                    throw;
                }
                return(0);
            }
            finally
            {
                TraceManager.CloudStorageComponent.TraceOut(callToken, blobCount);
            }
        }
Пример #9
0
        private KeyValuePair <BlobProperties, T> GetBlob <T>(string containerName, string blobName)
        {
            Guard.ArgumentNotNullOrEmptyString(containerName, "containerName");
            Guard.ArgumentNotNullOrEmptyString(blobName, "blobName");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(containerName, blobName);

            MemoryStream blobData       = null;
            object       blobObject     = null;
            bool         isBlobAsStream = IsStreamType(typeof(T));

            try
            {
                var container = this.blobStorage.GetContainerReference(CloudUtility.GetSafeContainerName(containerName));
                var cloudBlob = container.GetBlobReference(blobName);

                blobData = new MemoryStream();

                this.retryPolicy.ExecuteAction(() =>
                {
                    blobData.Seek(0, SeekOrigin.Begin);
                    cloudBlob.DownloadToStream(blobData);
                });

                blobData.Seek(0, SeekOrigin.Begin);

                // If blob type is a stream, just return the memory stream.
                if (isBlobAsStream)
                {
                    blobObject = blobData;
                }
                else
                {
                    // Otherwise, deserialize the underlying object from the blob data.
                    blobObject = this.dataSerializer.Deserialize(blobData, typeof(T));
                }

                return(new KeyValuePair <BlobProperties, T>(cloudBlob.Properties, (T)blobObject));
            }
            catch (StorageClientException ex)
            {
                // If blob doesn't exist, do not re-throw the exception, simply return a null reference.
                if (!(ex.ErrorCode == StorageErrorCode.ContainerNotFound || ex.ErrorCode == StorageErrorCode.BlobNotFound || ex.ErrorCode == StorageErrorCode.ResourceNotFound))
                {
                    throw;
                }
            }
            finally
            {
                // Should dispose the working stream unless it must be returned to the caller.
                if (blobData != null && !isBlobAsStream)
                {
                    blobData.Dispose();
                }

                TraceManager.CloudStorageComponent.TraceOut(callToken);
            }

            // Always return a non-null name/value pair, however do return a null reference to both the blob and its properties.
            return(new KeyValuePair <BlobProperties, T>());
        }
Пример #10
0
        /// <summary>
        /// Puts a blob into the underlying storage and returns its eTag value.
        /// If the blob with the same name already exists, overwrite behavior can be applied.
        /// </summary>
        /// <typeparam name="T">The type of the payload associated with the blob.</typeparam>
        /// <param name="containerName">The target blob container name into which a blob will be stored.</param>
        /// <param name="blobName">The custom name associated with the blob.</param>
        /// <param name="blob">The blob's payload.</param>
        /// <param name="overwrite">The flag indicating whether or not overwriting the existing blob is permitted.</param>
        /// <param name="expectedEtag">The parameters holding the blob's expected eTag value.</param>
        /// <param name="actualEtag">The output parameters holding the blob's actual eTag value.</param>
        /// <returns>True if the blob was successfully put into the specified container, otherwise false.</returns>
        private bool Put <T>(string containerName, string blobName, T blob, bool overwrite, string expectedEtag, out string actualEtag)
        {
            Guard.ArgumentNotNullOrEmptyString(containerName, "containerName");
            Guard.ArgumentNotNullOrEmptyString(blobName, "blobName");
            Guard.ArgumentNotNull(blob, "blob");

            var callToken = TraceManager.CloudStorageComponent.TraceIn(containerName, blobName, overwrite, expectedEtag);

            // Verify whether or not the specified blob is already of type Stream.
            Stream blobStream = IsStreamType(blob.GetType()) ? blob as Stream : null;
            Stream blobData   = null;

            actualEtag = null;

            try
            {
                // Are we dealing with a stream already? If yes, just use it as is.
                if (blobStream != null)
                {
                    blobData = blobStream;
                }
                else
                {
                    // The specified blob is something else rather than a Stream, we perform serialization of T into a new stream instance.
                    blobData = new MemoryStream();
                    this.dataSerializer.Serialize(blob, blobData);
                }

                var container = this.blobStorage.GetContainerReference(CloudUtility.GetSafeContainerName(containerName));
                StorageErrorCode lastErrorCode = StorageErrorCode.None;

                Func <string> uploadAction = () =>
                {
                    var cloudBlob = container.GetBlobReference(blobName);
                    return(UploadBlob(cloudBlob, blobData, overwrite, expectedEtag));
                };

                try
                {
                    // First attempt - perform upload and let the UploadBlob method handle any retry conditions.
                    string eTag = uploadAction();

                    if (!String.IsNullOrEmpty(eTag))
                    {
                        actualEtag = eTag;
                        return(true);
                    }
                }
                catch (StorageClientException ex)
                {
                    lastErrorCode = ex.ErrorCode;

                    if (!(lastErrorCode == StorageErrorCode.ContainerNotFound || lastErrorCode == StorageErrorCode.ResourceNotFound || lastErrorCode == StorageErrorCode.BlobAlreadyExists))
                    {
                        // Anything other than "not found" or "already exists" conditions will be considered as a runtime error.
                        throw;
                    }
                }

                if (lastErrorCode == StorageErrorCode.ContainerNotFound)
                {
                    // Failover action #1: create the target container and try again. This time, use a retry policy to wrap calls to the UploadBlob method.
                    string eTag = this.retryPolicy.ExecuteAction <string>(() =>
                    {
                        CreateContainer(containerName);
                        return(uploadAction());
                    });

                    return(!String.IsNullOrEmpty(actualEtag = eTag));
                }

                if (lastErrorCode == StorageErrorCode.BlobAlreadyExists && overwrite)
                {
                    // Failover action #2: Overwrite was requested but BlobAlreadyExists has still been returned. Delete the original blob and try to upload again.
                    string eTag = this.retryPolicy.ExecuteAction <string>(() =>
                    {
                        var cloudBlob = container.GetBlobReference(blobName);
                        cloudBlob.DeleteIfExists();

                        return(uploadAction());
                    });

                    return(!String.IsNullOrEmpty(actualEtag = eTag));
                }
            }
            finally
            {
                // Only dispose the blob data stream if it was newly created.
                if (blobData != null && null == blobStream)
                {
                    blobData.Dispose();
                }

                TraceManager.CloudStorageComponent.TraceOut(callToken, actualEtag);
            }

            return(false);
        }
Пример #11
0
        /// <summary>
        /// Gets a collection of messages from the specified queue and applies the specified visibility timeout.
        /// </summary>
        /// <typeparam name="T">The type of the payload associated with the message.</typeparam>
        /// <param name="queueName">The name of the source queue.</param>
        /// <param name="count">The number of messages to retrieve.</param>
        /// <param name="visibilityTimeout">The timeout during which retrieved messages will remain invisible on the queue.</param>
        /// <returns>The list of messages retrieved from the specified queue.</returns>
        public IEnumerable <T> Get <T>(string queueName, int count, TimeSpan visibilityTimeout)
        {
            Guard.ArgumentNotNullOrEmptyString(queueName, "queueName");
            Guard.ArgumentNotZeroOrNegativeValue(count, "count");

            try
            {
                var queue = this.queueStorage.GetQueueReference(CloudUtility.GetSafeContainerName(queueName));

                IEnumerable <CloudQueueMessage> queueMessages = this.retryPolicy.ExecuteAction <IEnumerable <CloudQueueMessage> >(() =>
                {
                    return(queue.GetMessages(Math.Min(count, CloudQueueMessage.MaxNumberOfMessagesToPeek), visibilityTimeout));
                });

                if (queueMessages != null)
                {
                    Type queueMsgType = typeof(T);
                    var  messages     = new List <T>(count);

                    foreach (var queueMsg in queueMessages)
                    {
                        object msgObject = DeserializeQueueMessage(queueMsg, queueMsgType);

                        // Construct an in-flight message object describing the queued message.
                        InflightMessageInfo inflightMessage = new InflightMessageInfo()
                        {
                            QueueName = queue.Name
                        };

                        // Register the queued message so that it can be located later on.
                        inflightMessage.QueueMessages.Add(queueMsg);

                        if (msgObject is LargeQueueMessageInfo)
                        {
                            // Looks like we are dealing a large message that needs to be fetched from blob storage.
                            inflightMessage.LargeMessageMetadata = msgObject as LargeQueueMessageInfo;

                            // Attempt to retrieve the actual message data from the blob storage.
                            T msgData = this.overflowStorage.Get <T>(inflightMessage.LargeMessageMetadata.ContainerName, inflightMessage.LargeMessageMetadata.BlobReference);

                            // If blob was found, add it to the list of messages being fetched and returned.
                            if (msgData != null)
                            {
                                messages.Add(msgData);
                                msgObject = msgData;
                            }
                            else
                            {
                                // We should skip the current message as it's data has not been located.
                                continue;
                            }
                        }
                        else
                        {
                            messages.Add((T)msgObject);
                        }

                        // Update the in-flight collection, add a new item if necessary, otherwise perform a thread-safe update.
                        this.inflightMessages.AddOrUpdate(msgObject, inflightMessage, (key, oldValue) =>
                        {
                            oldValue.QueueMessages.Clear();
                            return(inflightMessage);
                        });
                    }

                    return(messages);
                }
            }
            catch (Exception ex)
            {
                // We intend to never fail when fetching messages from a queue. We will still need to report on a exception and return an empty list.
                TraceManager.CloudStorageComponent.TraceError(ex);
            }

            // By default, return an empty collection of messages if the above code path didn't return a result.
            return(new T[0]);
        }