Source

main / Source / WebClient / Web.DataLayer / BlobDataRepository.cs

Naethra D 3ee1b94 





















































































































































































































































































































































using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using DataUp.Web.Common;

namespace DataUp.Web.DataLayer
{
    /// <summary>
    /// Class representing the Blob Data Repository having methods for adding/retrieving files from
    /// Azure blob storage.
    /// </summary>
    public class BlobDataRepository : IBlobDataRepository
    {
        private static Lazy<CloudBlobClient> lazyClient;
        private CloudStorageAccount storageAccount;

        /// <summary>
        /// Initializes a new instance of the <see cref="BlobDataRepository"/> class.
        /// </summary>
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Code does not grant its callers access to operations or resources that can be used in a destructive manner.")]
        public BlobDataRepository()
        {
            storageAccount = CloudStorageAccount.FromConfigurationSetting(Constants.StorageSettingName);
            lazyClient = new Lazy<CloudBlobClient>(() => (this.storageAccount.CreateCloudBlobClient()));
        }

        /// <summary>
        /// Gets the container URL.
        /// </summary>
        public static Uri ContainerUrl
        {
            get
            {
                return new Uri(string.Join(Constants.PathSeparator, new string[] { BlobClient.BaseUri.AbsolutePath, Constants.ContainerName }));
            }
        }

        /// <summary>
        /// Gets the CloudBlobClient instance from lazyclient.
        /// </summary>
        private static CloudBlobClient BlobClient
        {
            get
            {
                CloudBlobClient blobclient = lazyClient.Value;
                blobclient.RetryPolicy = Constants.DefaultRetryPolicy;
                return blobclient;
            }
        }

        /// <summary>
        /// Gets the blob content from azure as a stream.
        /// </summary>
        /// <param name="blobName">
        /// Name of the blob.
        /// </param>
        /// <returns>
        /// The blob details.
        /// </returns>
        public BlobDetails GetBlobContent(string blobName)
        {
            if (string.IsNullOrWhiteSpace(blobName))
            {
                throw new ArgumentNullException("blobName");
            }

            return GetBlob(blobName, Constants.ContainerName);
        }

        /// <summary>
        /// Uploads a file to azure as a blob.
        /// </summary>
        /// <param name="details">
        /// Details of the file which has to be uploaded to azure.
        /// </param>
        /// <returns>
        /// True if the file is uploaded successfully; otherwise false.
        /// </returns>
        public bool UploadFile(BlobDetails details)
        {
            this.CheckNotNull(() => details);

            return UploadBlobContent(details, Constants.ContainerName);
        }

        /// <summary>
        /// Deletes a file from azure.
        /// </summary>
        /// <param name="details">
        /// Details of the file which has to be uploaded to azure.
        /// </param>
        /// <returns>
        /// True if the file is deleted successfully; otherwise false.
        /// </returns>
        public bool DeleteFile(BlobDetails details)
        {
            return DeleteBlob(details, Constants.ContainerName);
        }

        /// <summary>
        /// Checks a file in azure.
        /// </summary>
        /// <param name="details">
        /// Details of the file which has to be checked.
        /// </param>
        /// <returns>
        /// True if the file is found successfully; otherwise false.
        /// </returns>
        public bool CheckIfExists(BlobDetails details)
        {
            return ExistsBlobContent(details, Constants.ContainerName);
        }

        /// <summary>
        /// Gets the content from azure as a stream.
        /// </summary>
        /// <param name="blobName">
        /// Name of the blob.
        /// </param>
        /// <param name="outputStream">
        /// The content is exposed as output stream.
        /// </param>
        /// <param name="container">
        /// COntainer where we could find the blob.
        /// </param>
        /// <returns>
        /// The blob properties.
        /// </returns>
        private static BlobProperties GetContent(string blobName, Stream outputStream, CloudBlobContainer container)
        {
            var blob = container.GetBlobReference(blobName.ToUpperInvariant());
            blob.DownloadToStream(outputStream, new BlobRequestOptions() { Timeout = TimeSpan.FromMinutes(30) });
            return blob.Properties;
        }

        /// <summary>
        /// Used to retrieve the container reference identified by the container name.
        /// </summary>
        /// <param name="containerName">
        /// Name of the container.
        /// </param>
        /// <returns>
        /// Container instance.
        /// </returns>
        private static CloudBlobContainer GetContainer(string containerName)
        {
            // TODO: Need to make sure the container is created. This was commented out as this was 
            //      proving to be a redundant call to azure and to improve performance
            var blobContainer = new CloudBlobContainer(containerName, BlobClient);
            return blobContainer;
        }

        /// <summary>
        /// Gets the content of the blob from specified container.
        /// </summary>
        /// <param name="blobName">
        /// Name of the blob.
        /// </param>
        /// <param name="containerName">
        /// name of the container.
        /// </param>
        /// <returns>
        /// The blob details.
        /// </returns>
        private static BlobDetails GetBlob(string blobName, string containerName)
        {
            Stream outputStream = null;
            BlobProperties properties = null;
            try
            {
                outputStream = new MemoryStream();
                CloudBlobContainer container = GetContainer(containerName);
                properties = GetContent(blobName, outputStream, container);
            }
            catch (InvalidOperationException)
            {
                // TODO: Add error handling logic
                // "Error getting contents of blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, sc.Message
                outputStream = null;
            }
            catch (StorageClientException)
            {
                // TODO: Add error handling logic
                // ErrorCode and StatusCode can be used to identify the error.
                // "Error getting contents of blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, sc.Message

                // TODO: Need to add proper Exception handling.
                outputStream = null;
            }

            return new BlobDetails()
            {
                Data = outputStream,
                BlobID = blobName,
                MimeType = properties != null ? properties.ContentType : Constants.DefaultMimeType
            };
        }

        /// <summary>
        /// Moves blob from source to destination.
        /// </summary>
        /// <param name="details">
        /// Details of the blob.
        /// </param>
        /// <param name="sourceContainerName">
        /// Name of Source container.
        /// </param>
        /// <param name="destinationContainerName">
        /// Name of Destination container.
        /// </param>
        /// <returns>
        /// True, if the blob is successfully moved;otherwise false.
        /// </returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Ignore all exceptions.")]
        private static bool MoveBlob(BlobDetails details, string sourceContainerName, string destinationContainerName)
        {
            try
            {
                var sourceContainer = GetContainer(sourceContainerName);
                var destinationContainer = GetContainer(destinationContainerName);

                // TODO: Check if the input file type and then use either block blob or page blob.
                // For plate file we need to upload the file as page blob.
                var sourceBlob = sourceContainer.GetBlockBlobReference(details.BlobID.ToUpperInvariant());
                var destinationBlob = destinationContainer.GetBlockBlobReference(details.BlobID.ToUpperInvariant());

                destinationBlob.CopyFromBlob(sourceBlob);
                destinationBlob.Properties.ContentType = sourceBlob.Properties.ContentType;
                sourceBlob.Delete();
                return true;
            }
            catch (Exception)
            {
                // "Error moving blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, se.Message
            }

            return false;
        }

        /// <summary>
        /// Checks if the blob content is present in azure or not.
        /// </summary>
        /// <param name="details">
        /// Details of the blob.
        /// </param>
        /// <param name="containerName">
        /// Name of the container.
        /// </param>
        /// <returns>
        /// True, if the blob is successfully found to azure;otherwise false.
        /// </returns>
        private static bool ExistsBlobContent(BlobDetails details, string containerName)
        {
            try
            {
                CloudBlobContainer container = GetContainer(containerName);

                // TODO: Check if the input file type and then use either block blob or page blob.
                // For plate file we need to upload the file as page blob.
                var blob = container.GetBlobReference(details.BlobID.ToUpperInvariant());
                blob.FetchAttributes();

                return true;
            }
            catch (StorageClientException)
            {
                // "Error uploading blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, se.Message
            }

            return false;
        }

        /// <summary>
        /// Deletes the specified file pointed by the blob.
        /// </summary>
        /// <param name="details">
        /// Details of the blob.
        /// </param>
        /// <param name="containerName">
        /// Name of the container.
        /// </param>
        private static bool DeleteBlob(BlobDetails details, string containerName)
        {
            try
            {
                CloudBlobContainer container = GetContainer(containerName);

                container.GetBlobReference(details.BlobID.ToUpperInvariant()).Delete();
                return true;
            }
            catch (InvalidOperationException)
            {
                // "Error deleting blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, se.Message
                return false;
            }
        }

        /// <summary>
        /// Upload the blob content to azure.
        /// </summary>
        /// <param name="details">
        /// Details of the blob.
        /// </param>
        /// <param name="containerName">
        /// Name of the container.
        /// </param>
        /// <returns>
        /// True, if the blob is successfully uploaded to azure;otherwise false.
        /// </returns>
        private bool UploadBlobContent(BlobDetails details, string containerName)
        {
            this.CheckNotNull(() => details);

            try
            {
                CloudBlobContainer container = GetContainer(containerName);

                // Seek to start.
                details.Data.Position = 0;

                // TODO: Check if the input file type and then use either block blob or page blob.
                // For plate file we need to upload the file as page blob.
                var blob = container.GetBlockBlobReference(details.BlobID.ToUpperInvariant());
                blob.Attributes.Properties.ContentType = details.MimeType;
                blob.UploadFromStream(details.Data, new BlobRequestOptions() { Timeout = TimeSpan.FromMinutes(30) });

                return true;
            }
            catch (InvalidOperationException)
            {
                // "Error uploading blob {0}: {1}", ContainerUrl + _PathSeparator + blobName, se.Message
            }

            return false;
        }
    }
}