private void RunUploadLoop(
            BlobTransferContext transferContext,
            FileStream fileStream,
            int numThreads)
        {
            SpinWait spinWait = new SpinWait();

            while (!transferContext.IsComplete && !transferContext.CancellationToken.IsCancellationRequested)
            {
                if (!transferContext.IsReadingOrWriting)
                {
                    DoSequentialRead(transferContext, fileStream);
                }

                if (!transferContext.IsComplete &&
                    transferContext.NumInProgressUploadDownloads < numThreads)
                {
                    TryUploadingBlocks(transferContext);
                }
                spinWait.SpinOnce();
            }

            while (transferContext.NumInProgressUploadDownloads > 0 || transferContext.IsReadingOrWriting)
            {
                spinWait.SpinOnce();
            }

            foreach (var memoryStream in transferContext.BufferStreams.Values)
            {
                memoryStream.Dispose();
            }

            transferContext.OnComplete();
        }
Esempio n. 2
0
        private void RunUploadLoop(
            BlobTransferContext transferContext,
            Stream fileStream,
            int numThreads)
        {
            SpinWait spinWait = new SpinWait();

            while (!transferContext.IsComplete && !transferContext.CancellationToken.IsCancellationRequested)
            {
                if (!transferContext.IsReadingOrWriting)
                {
                    DoSequentialRead(transferContext, fileStream);
                }

                if (!transferContext.IsComplete &&
                    transferContext.NumInProgressUploadDownloads < numThreads)
                {
                    TryUploadingBlocks(transferContext);
                }
                spinWait.SpinOnce();
            }

            while (transferContext.NumInProgressUploadDownloads > 0 || transferContext.IsReadingOrWriting)
            {
                spinWait.SpinOnce();
            }

            //Release any buffers that are still in queue to be written to file but could not because there was
            // a complete signal for this file upload due to some error in the one of the other block uploads in the same transfer context.
            //If this is not cleaned, used buffers will hit the cap of 16 and future uploads will hang for lack of memory buffers.
            for (int currentBlock = transferContext.NextFileIOBlock; currentBlock <= transferContext.BlocksForFileIO.Count(); currentBlock++)
            {
                byte[] buffer = null;

                if (transferContext.BlocksForFileIO.TryGetValue(currentBlock, out buffer) && (buffer != null))
                {
                    try
                    {
                        transferContext.MemoryManager.ReleaseBuffer(buffer);
                    }
                    catch (ArgumentException ex)
                    {
                        Debug.WriteLine("Exception occured while releasing memory buffer ", ex.Message);
                    }
                }
            }
            foreach (var memoryStream in transferContext.BufferStreams.Values)
            {
                memoryStream.Dispose();
            }

            transferContext.OnComplete();
        }
        private void UploadFileToBlob(
            CancellationToken cancellationToken,
            Uri uri,
            string localFile,
            string contentType,
            string subDirectory,
            FileEncryption fileEncryption,
            CloudBlobClient client,
            IRetryPolicy retryPolicy,
            Func<string> getSharedAccessSignature,
            int parallelTransferThreadCount,
            bool shouldDoFileIO = true)
        {
            BlobTransferContext transferContext = new BlobTransferContext();
            transferContext.Exceptions = new ConcurrentBag<Exception>();
            try
            {
                    ManualResetEvent uploadCompletedSignal = new ManualResetEvent(false);
                    BlobRequestOptions blobRequestOptions = new BlobRequestOptions
                    {
                        RetryPolicy = retryPolicy,
                        ServerTimeout = TimeSpan.FromSeconds(90)
                    };
                    //attempt to open the file first so that we throw an exception before getting into the async work
                    using (FileStream fileStream = new FileStream(localFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                    }
                    CloudBlockBlob blob = GetCloudBlockBlob(uri, client, subDirectory, localFile, contentType,
                        getSharedAccessSignature);
                    BlobPolicyActivationWait(() => blob.DeleteIfExists(options: blobRequestOptions));

                    FileInfo file = new FileInfo(localFile);
                    long fileSize = file.Length;
                    transferContext.Length = fileSize;
                    transferContext.LocalFilePath = localFile;
                    transferContext.OnComplete = () => uploadCompletedSignal.Set();
                    transferContext.Blob = blob;
                    transferContext.FileEncryption = fileEncryption;
                    if (fileSize == 0)
                    {
                        blob.UploadFromByteArray(new byte[1], 0, 0, options: blobRequestOptions);
                    }
                    else if (fileSize < cloudBlockBlobUploadDownloadSizeLimit)
                    {
                        AccessCondition accessCondition = AccessCondition.GenerateEmptyCondition();
                        OperationContext operationContext = new OperationContext();
                        operationContext.ClientRequestID = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);
                        using (FileStream fileStream = new FileStream(localFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                        {
                               using (var memoryStream = new MemoryStream())
                                     {
                                         fileStream.CopyTo(memoryStream);
                                         byte[] fileContent = memoryStream.ToArray();
                                         ApplyEncryptionTransform(
                                                     transferContext.FileEncryption,
                                                     Path.GetFileName(transferContext.LocalFilePath),
                                                     0,
                                                     fileContent,
                                                     Convert.ToInt32(fileStream.Length));
                                         using (var uploadMemoryStream = new MemoryStream(fileContent))
                                         {
                                             blob.UploadFromStream(uploadMemoryStream, accessCondition: accessCondition, options: blobRequestOptions, operationContext: operationContext);
                                         }
                                     }
                        }
                        InvokeProgressCallback(transferContext, fileSize, fileSize);
                        transferContext.OnComplete();
                    }
                    else
                    {
                        int numThreads = parallelTransferThreadCount;
                        int blockSize = GetBlockSize(fileSize);

                        transferContext.BlocksToTransfer = PrepareUploadDownloadQueue(fileSize, blockSize, ref numThreads);

                        transferContext.BlocksForFileIO = new ConcurrentDictionary<int, byte[]>();
                        for (int i = 0; i < transferContext.BlocksToTransfer.Count(); i++)
                        {
                            transferContext.BlocksForFileIO[i] = null;
                        }
                        transferContext.BlockSize = blockSize;
                        transferContext.CancellationToken = cancellationToken;
                        transferContext.BlobRequestOptions = blobRequestOptions;
                        transferContext.MemoryManager = MemoryManagerFactory.GetMemoryManager(blockSize);
                        transferContext.Client = client;
                        transferContext.RetryPolicy = retryPolicy;
                        transferContext.GetSharedAccessSignature = getSharedAccessSignature;
                        transferContext.ShouldDoFileIO = shouldDoFileIO;
                        transferContext.BufferStreams = new ConcurrentDictionary<byte[], MemoryStream>();
                        transferContext.ClientRequestId = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);
                        transferContext.ContentType = contentType;
                        transferContext.BlobSubFolder = subDirectory;
                        transferContext.NextFileIOBlock = 0;
                        transferContext.PartialFileIOState = new ConcurrentDictionary<long, int>();

                        using (
                            FileStream stream = new FileStream(localFile, FileMode.Open, FileAccess.Read,
                                FileShare.ReadWrite))
                        {
                            RunUploadLoop(transferContext, stream, numThreads);
                        }
                }
            }
            catch (Exception e)
            {
                //Add the exception to the exception list.
                transferContext.Exceptions.Add(e);
            }
            finally
            {
                // We should to be able to releaseunusedbuffers if memorymanager was initialized by then
                if (transferContext.MemoryManager != null)
                {
                    transferContext.MemoryManager.ReleaseUnusedBuffers();

                }
                //TaskCompletedCallback should be called to populate exceptions if relevant and other eventargs for the user.
                TaskCompletedCallback(
                    cancellationToken.IsCancellationRequested,
                    transferContext.Exceptions != null && transferContext.Exceptions.Count > 0
                        ? new AggregateException(transferContext.Exceptions)
                        : null,
                    BlobTransferType.Upload,
                    localFile,
                    uri);
            }
        }
        private void RunUploadLoop(
            BlobTransferContext transferContext,
            FileStream fileStream,
            int numThreads)
        {
            SpinWait spinWait = new SpinWait();

            while (!transferContext.IsComplete && !transferContext.CancellationToken.IsCancellationRequested)
            {
                if (!transferContext.IsReadingOrWriting)
                {
                    DoSequentialRead(transferContext, fileStream);
                }

                if (!transferContext.IsComplete &&
                    transferContext.NumInProgressUploadDownloads < numThreads)
                {
                    TryUploadingBlocks(transferContext);
                }
                spinWait.SpinOnce();
            }

            while (transferContext.NumInProgressUploadDownloads > 0 || transferContext.IsReadingOrWriting)
            {
                spinWait.SpinOnce();
            }

            //Release any buffers that are still in queue to be written to file but could not because there was
            // a complete signal for this file upload due to some error in the one of the other block uploads in the same transfer context.
            //If this is not cleaned, used buffers will hit the cap of 16 and future uploads will hang for lack of memory buffers.
            for (int currentBlock = transferContext.NextFileIOBlock; currentBlock <= transferContext.BlocksForFileIO.Count(); currentBlock++)
            {
                byte[] buffer = null;

                if (transferContext.BlocksForFileIO.TryGetValue(currentBlock, out buffer) && (buffer != null))
                {
                    try
                    {
                        transferContext.MemoryManager.ReleaseBuffer(buffer);
                    }
                    catch (ArgumentException ex)
                    {
                        Debug.WriteLine("Exception occured while releasing memory buffer ", ex.Message);
                    }

                }
            }
            foreach (var memoryStream in transferContext.BufferStreams.Values)
            {
                memoryStream.Dispose();
            }

            transferContext.OnComplete();
        }
Esempio n. 5
0
        private void UploadFileToBlob(
            CancellationToken cancellationToken,
            Uri uri,
            string name,
            Stream stream,
            string contentType,
            string subDirectory,
            FileEncryption fileEncryption,
            CloudBlobClient client,
            IRetryPolicy retryPolicy,
            Func <string> getSharedAccessSignature,
            int parallelTransferThreadCount,
            bool shouldDoFileIO = true)
        {
            BlobTransferContext transferContext = new BlobTransferContext();

            transferContext.Exceptions = new ConcurrentBag <Exception>();
            try
            {
                ManualResetEvent   uploadCompletedSignal = new ManualResetEvent(false);
                BlobRequestOptions blobRequestOptions    = new BlobRequestOptions
                {
                    RetryPolicy   = retryPolicy,
                    ServerTimeout = TimeSpan.FromSeconds(90)
                };

                CloudBlockBlob blob = GetCloudBlockBlob(uri, client, subDirectory, name, contentType, getSharedAccessSignature);

                transferContext.Length         = stream.Length;
                transferContext.LocalFilePath  = name;
                transferContext.OnComplete     = () => uploadCompletedSignal.Set();
                transferContext.Blob           = blob;
                transferContext.FileEncryption = fileEncryption;
                if (stream.Length == 0)
                {
                    blob.UploadFromByteArray(new byte[1], 0, 0, options: blobRequestOptions);
                }
                else if (stream.Length < cloudBlockBlobUploadDownloadSizeLimit)
                {
                    AccessCondition  accessCondition  = AccessCondition.GenerateEmptyCondition();
                    OperationContext operationContext = new OperationContext();
                    operationContext.ClientRequestID = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);

                    using (var memoryStream = new MemoryStream())
                    {
                        stream.CopyTo(memoryStream);
                        byte[] fileContent = memoryStream.ToArray();
                        ApplyEncryptionTransform(
                            transferContext.FileEncryption,
                            Path.GetFileName(transferContext.LocalFilePath),
                            0,
                            fileContent,
                            Convert.ToInt32(stream.Length));

                        using (var uploadMemoryStream = new MemoryStream(fileContent))
                        {
                            blob.UploadFromStream(uploadMemoryStream, accessCondition: accessCondition, options: blobRequestOptions, operationContext: operationContext);
                        }
                    }
                    InvokeProgressCallback(transferContext, stream.Length, stream.Length);
                    transferContext.OnComplete();
                }
                else
                {
                    int numThreads = parallelTransferThreadCount;
                    int blockSize  = GetBlockSize(stream.Length);

                    transferContext.BlocksToTransfer = PrepareUploadDownloadQueue(stream.Length, blockSize, ref numThreads);

                    transferContext.BlocksForFileIO = new ConcurrentDictionary <int, byte[]>();
                    for (int i = 0; i < transferContext.BlocksToTransfer.Count(); i++)
                    {
                        transferContext.BlocksForFileIO[i] = null;
                    }
                    transferContext.BlockSize                = blockSize;
                    transferContext.CancellationToken        = cancellationToken;
                    transferContext.BlobRequestOptions       = blobRequestOptions;
                    transferContext.MemoryManager            = MemoryManagerFactory.GetMemoryManager(blockSize);
                    transferContext.Client                   = client;
                    transferContext.RetryPolicy              = retryPolicy;
                    transferContext.GetSharedAccessSignature = getSharedAccessSignature;
                    transferContext.ShouldDoFileIO           = shouldDoFileIO;
                    transferContext.BufferStreams            = new ConcurrentDictionary <byte[], MemoryStream>();
                    transferContext.ClientRequestId          = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);
                    transferContext.ContentType              = contentType;
                    transferContext.BlobSubFolder            = subDirectory;
                    transferContext.NextFileIOBlock          = 0;
                    transferContext.PartialFileIOState       = new ConcurrentDictionary <long, int>();

                    RunUploadLoop(transferContext, stream, numThreads);
                }
            }
            catch (Exception e)
            {
                //Add the exception to the exception list.
                transferContext.Exceptions.Add(e);
            }
            finally
            {
                // We should to be able to releaseunusedbuffers if memorymanager was initialized by then
                if (transferContext.MemoryManager != null)
                {
                    transferContext.MemoryManager.ReleaseUnusedBuffers();
                }
                //TaskCompletedCallback should be called to populate exceptions if relevant and other eventargs for the user.
                TaskCompletedCallback(
                    cancellationToken.IsCancellationRequested,
                    transferContext.Exceptions != null && transferContext.Exceptions.Count > 0
                        ? new AggregateException(transferContext.Exceptions)
                        : null,
                    BlobTransferType.Upload,
                    name,
                    uri);
            }
        }
        private void DoSequentialWrite(
            BlobTransferContext transferContext,
            FileStream stream)
        {
            if (transferContext.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            byte[] buffer = null;

            if (transferContext.BlocksForFileIO.TryGetValue(transferContext.NextFileIOBlock, out buffer) && buffer != null)
            {
                transferContext.IsReadingOrWriting = true;
                long endOfRange = transferContext.Length + transferContext.InitialOffset;

                long beginFilePosition = (long)transferContext.NextFileIOBlock * transferContext.BlockSize + transferContext.InitialOffset;
                beginFilePosition = beginFilePosition > endOfRange
                    ? endOfRange
                    : beginFilePosition;

                long nextBeginFilePosition = (transferContext.NextFileIOBlock + 1) * (long)transferContext.BlockSize + transferContext.InitialOffset;
                nextBeginFilePosition = nextBeginFilePosition > endOfRange
                                            ? endOfRange
                                            : nextBeginFilePosition;

                int bytesToWrite = (int)(nextBeginFilePosition - beginFilePosition);

                ApplyEncryptionTransform(transferContext.FileEncryption, transferContext.InitializationVector, beginFilePosition, buffer, bytesToWrite);

                stream.BeginWrite(
                    buffer,
                    0,
                    bytesToWrite,
                    result3 =>
                    {

                        SuccessfulOrRetryableResult wasWriteSuccessful =
                            IsActionSuccessfulOrRetryable(transferContext, () => stream.EndWrite(result3));

                        transferContext.MemoryManager.ReleaseBuffer(buffer);

                        if (!wasWriteSuccessful.IsSuccessful)
                        {
                            transferContext.IsReadingOrWriting = false;
                            return;
                        }

                        transferContext.NextFileIOBlock++;

                        Interlocked.Add(ref transferContext.BytesWrittenOrReadToFile, bytesToWrite);

                        InvokeProgressCallback(transferContext, transferContext.BytesWrittenOrReadToFile, bytesToWrite);

                        transferContext.IsReadingOrWriting = false;

                        if (transferContext.BytesWrittenOrReadToFile >= transferContext.Length)
                        {
                            transferContext.IsComplete = true;
                            transferContext.OnComplete();
                        }
                    },
                    null);
            }
        }
        private void RunUploadLoop(
            BlobTransferContext transferContext,
            FileStream fileStream,
            int numThreads)
        {
            SpinWait spinWait = new SpinWait();

            while (!transferContext.IsComplete && !transferContext.CancellationToken.IsCancellationRequested)
            {
                if (!transferContext.IsReadingOrWriting)
                {
                    DoSequentialRead(transferContext, fileStream);
                }

                if (!transferContext.IsComplete &&
                    transferContext.NumInProgressUploadDownloads < numThreads)
                {
                    TryUploadingBlocks(transferContext);
                }
                spinWait.SpinOnce();
            }

            while (transferContext.NumInProgressUploadDownloads > 0 || transferContext.IsReadingOrWriting)
            {
                spinWait.SpinOnce();
            }

            foreach (var memoryStream in transferContext.BufferStreams.Values)
            {
                memoryStream.Dispose();
            }

            transferContext.OnComplete();
        }
Esempio n. 8
0
        private void DoSequentialWrite(
            BlobTransferContext transferContext,
            FileStream stream)
        {
            if (transferContext.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            byte[] buffer = null;

            if (transferContext.BlocksForFileIO.TryGetValue(transferContext.NextFileIOBlock, out buffer) && buffer != null)
            {
                transferContext.IsReadingOrWriting = true;
                long endOfRange = transferContext.Length + transferContext.InitialOffset;

                long beginFilePosition = (long)transferContext.NextFileIOBlock * transferContext.BlockSize + transferContext.InitialOffset;
                beginFilePosition = beginFilePosition > endOfRange
                    ? endOfRange
                    : beginFilePosition;

                long nextBeginFilePosition = (transferContext.NextFileIOBlock + 1) * (long)transferContext.BlockSize + transferContext.InitialOffset;
                nextBeginFilePosition = nextBeginFilePosition > endOfRange
                                            ? endOfRange
                                            : nextBeginFilePosition;

                int bytesToWrite = (int)(nextBeginFilePosition - beginFilePosition);

                ApplyEncryptionTransform(transferContext.FileEncryption, transferContext.InitializationVector, beginFilePosition, buffer, bytesToWrite);

                stream.BeginWrite(
                    buffer,
                    0,
                    bytesToWrite,
                    result3 =>
                {
                    SuccessfulOrRetryableResult wasWriteSuccessful =
                        IsActionSuccessfulOrRetryable(transferContext, () => stream.EndWrite(result3));

                    transferContext.MemoryManager.ReleaseBuffer(buffer);

                    if (!wasWriteSuccessful.IsSuccessful)
                    {
                        transferContext.IsReadingOrWriting = false;
                        return;
                    }

                    transferContext.NextFileIOBlock++;

                    Interlocked.Add(ref transferContext.BytesWrittenOrReadToFile, bytesToWrite);

                    InvokeProgressCallback(transferContext, transferContext.BytesWrittenOrReadToFile, bytesToWrite);

                    transferContext.IsReadingOrWriting = false;

                    if (transferContext.BytesWrittenOrReadToFile >= transferContext.Length)
                    {
                        transferContext.IsComplete = true;
                        transferContext.OnComplete();
                    }
                },
                    null);
            }
        }
        private void DownloadFileFromBlob(
            Uri uri,
            string localFile,
            FileEncryption fileEncryption,
            ulong initializationVector,
            CloudBlobClient client,
            CancellationToken cancellationToken,
            IRetryPolicy retryPolicy,
            Func <string> getSharedAccessSignature,
            bool shouldDoFileIO             = true,
            long start                      = 0,
            long length                     = -1,
            int parallelTransferThreadCount = 10)
        {
            ManualResetEvent   downloadCompletedSignal = new ManualResetEvent(false);
            BlobRequestOptions blobRequestOptions      = new BlobRequestOptions {
                RetryPolicy = retryPolicy
            };
            CloudBlockBlob      blob            = null;
            BlobTransferContext transferContext = new BlobTransferContext();

            transferContext.Exceptions = new ConcurrentBag <Exception>();

            try
            {
                blob = GetCloudBlockBlob(uri, client, retryPolicy, getSharedAccessSignature);

                long initialOffset  = start;
                long sizeToDownload = blob.Properties.Length;

                if (length != -1)
                {
                    if (length > blob.Properties.Length)
                    {
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                                  "Size {0} is beyond the Length of Blob {1}", length, blob.Properties.Length));
                    }

                    if (start + length > blob.Properties.Length)
                    {
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                                  "Size {0} plus offset {1} is beyond the Length of Blob {2}", length, start,
                                                                  blob.Properties.Length));
                    }

                    sizeToDownload = length;
                }
                transferContext.Length               = sizeToDownload;
                transferContext.LocalFilePath        = localFile;
                transferContext.OnComplete           = () => downloadCompletedSignal.Set();
                transferContext.Blob                 = blob;
                transferContext.FileEncryption       = fileEncryption;
                transferContext.InitializationVector = initializationVector;
                transferContext.InitialOffset        = start;

                if (sizeToDownload == 0)
                {
                    using (FileStream stream =
                               new FileStream(
                                   localFile,
                                   FileMode.OpenOrCreate,
                                   FileAccess.Write,
                                   FileShare.Read
                                   ))
                    {
                    }
                }
                else if (sizeToDownload < cloudBlockBlobUploadDownloadSizeLimit)
                {
                    AccessCondition  accessCondition  = AccessCondition.GenerateEmptyCondition();
                    OperationContext operationContext = new OperationContext();
                    operationContext.ClientRequestID = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);
                    using (FileStream fileStream = new FileStream(
                               transferContext.LocalFilePath,
                               FileMode.OpenOrCreate,
                               FileAccess.ReadWrite,
                               FileShare.Read
                               ))
                    {
                        blob.DownloadToStream(fileStream, accessCondition: accessCondition, options: blobRequestOptions, operationContext: operationContext);
                        if (fileEncryption != null)
                        {
                            using (MemoryStream msDecrypt = new MemoryStream())
                            {
                                //Using CryptoTransform APIs per Quintin's suggestion.
                                using (FileEncryptionTransform fileEncryptionTransform = fileEncryption.GetTransform(initializationVector, 0))
                                {
                                    fileStream.Position = 0;
                                    fileStream.CopyTo(msDecrypt);
                                    msDecrypt.Position  = 0;
                                    fileStream.Position = 0;
                                    using (CryptoStream csEncrypt = new CryptoStream(msDecrypt, fileEncryptionTransform, CryptoStreamMode.Read))
                                    {
                                        csEncrypt.CopyTo(fileStream);
                                    }
                                }
                            }
                        }
                    }
                    InvokeProgressCallback(transferContext, sizeToDownload, sizeToDownload);
                    transferContext.OnComplete();
                }
                else
                {
                    int numThreads = parallelTransferThreadCount;
                    int blockSize  = GetBlockSize(blob.Properties.Length);

                    transferContext.BlocksToTransfer = PrepareUploadDownloadQueue(sizeToDownload, blockSize,
                                                                                  ref numThreads, initialOffset);

                    transferContext.BlocksForFileIO = new ConcurrentDictionary <int, byte[]>();
                    for (int i = 0; i < transferContext.BlocksToTransfer.Count(); i++)
                    {
                        transferContext.BlocksForFileIO[i] = null;
                    }
                    transferContext.BlockSize                = blockSize;
                    transferContext.CancellationToken        = cancellationToken;
                    transferContext.BlobRequestOptions       = blobRequestOptions;
                    transferContext.MemoryManager            = MemoryManagerFactory.GetMemoryManager(blockSize);
                    transferContext.Client                   = client;
                    transferContext.RetryPolicy              = retryPolicy;
                    transferContext.GetSharedAccessSignature = getSharedAccessSignature;
                    transferContext.ShouldDoFileIO           = shouldDoFileIO;
                    transferContext.BufferStreams            = new ConcurrentDictionary <byte[], MemoryStream>();
                    transferContext.ClientRequestId          = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);

                    using (FileStream stream = new FileStream(
                               transferContext.LocalFilePath,
                               FileMode.OpenOrCreate,
                               FileAccess.Write,
                               FileShare.Read
                               ))
                    {
                        stream.SetLength(sizeToDownload);
                        RunDownloadLoop(transferContext, stream, numThreads);
                    }
                }
            }
            catch (Exception e)
            {
                //Add the exception to the exception list.
                transferContext.Exceptions.Add(e);
            }
            finally
            {
                // We should to be able to releaseunusedbuffers if memorymanager was initialized by then
                if (transferContext.MemoryManager != null)
                {
                    transferContext.MemoryManager.ReleaseUnusedBuffers();
                }
                //TaskCompletedCallback should be called to populate exceptions if relevant and other eventargs for the user.
                TaskCompletedCallback(
                    cancellationToken.IsCancellationRequested,
                    transferContext.Exceptions != null && transferContext.Exceptions.Count > 0
                            ? new AggregateException(transferContext.Exceptions)
                            : null,
                    BlobTransferType.Download,
                    localFile,
                    uri);
            }
        }
        private void DownloadFileFromBlob(
            Uri uri,
            string localFile,
            FileEncryption fileEncryption,
            ulong initializationVector,
            CloudBlobClient client,
            CancellationToken cancellationToken,
            IRetryPolicy retryPolicy,
            Func<string> getSharedAccessSignature,
            bool shouldDoFileIO = true,
            long start = 0,
            long length = -1,
            int parallelTransferThreadCount = 10)
        {
            ManualResetEvent downloadCompletedSignal = new ManualResetEvent(false);
            BlobRequestOptions blobRequestOptions = new BlobRequestOptions { RetryPolicy = retryPolicy };
            CloudBlockBlob blob = null;
            BlobTransferContext transferContext = new BlobTransferContext();
            transferContext.Exceptions = new ConcurrentBag<Exception>();

            try
            {
                blob = GetCloudBlockBlob(uri, client, retryPolicy, getSharedAccessSignature);

                long initialOffset = start;
                long sizeToDownload = blob.Properties.Length;

                if (length != -1)
                {
                    if (length > blob.Properties.Length)
                    {
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                            "Size {0} is beyond the Length of Blob {1}", length, blob.Properties.Length));
                    }

                    if (start + length > blob.Properties.Length)
                    {
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                            "Size {0} plus offset {1} is beyond the Length of Blob {2}", length, start,
                            blob.Properties.Length));
                    }

                    sizeToDownload = length;
                }
                transferContext.Length = sizeToDownload;
                transferContext.LocalFilePath = localFile;
                transferContext.OnComplete = () => downloadCompletedSignal.Set();
                transferContext.Blob = blob;
                transferContext.FileEncryption = fileEncryption;
                transferContext.InitializationVector = initializationVector;
                transferContext.InitialOffset = start;

                if (sizeToDownload == 0)
                {
                    using (FileStream stream =
                        new FileStream(
                            localFile,
                            FileMode.OpenOrCreate,
                            FileAccess.Write,
                            FileShare.Read
                            ))
                    {
                    }

                }
                else if (sizeToDownload < cloudBlockBlobUploadDownloadSizeLimit)
                {
                    AccessCondition accessCondition = AccessCondition.GenerateEmptyCondition();
                    OperationContext operationContext = new OperationContext();
                    operationContext.ClientRequestID = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);
                    using (FileStream fileStream = new FileStream(
                        transferContext.LocalFilePath,
                        FileMode.OpenOrCreate,
                        FileAccess.ReadWrite,
                        FileShare.Read
                        ))
                    {
                        blob.DownloadToStream(fileStream, accessCondition: accessCondition, options: blobRequestOptions, operationContext: operationContext);
                        if (fileEncryption != null)
                        {
                            using (MemoryStream msDecrypt = new MemoryStream())
                            {
                                //Using CryptoTransform APIs per Quintin's suggestion.
                                using (FileEncryptionTransform fileEncryptionTransform = fileEncryption.GetTransform(initializationVector, 0))
                                {
                                    fileStream.Position = 0;
                                    fileStream.CopyTo(msDecrypt);
                                    msDecrypt.Position = 0;
                                    fileStream.Position = 0;
                                    using (CryptoStream csEncrypt = new CryptoStream(msDecrypt, fileEncryptionTransform, CryptoStreamMode.Read))
                                    {
                                        csEncrypt.CopyTo(fileStream);
                                    }
                                }
                            }

                        }
                   }
                    InvokeProgressCallback(transferContext, sizeToDownload, sizeToDownload);
                    transferContext.OnComplete();
                }
                else
                {
                    int numThreads = parallelTransferThreadCount;
                    int blockSize = GetBlockSize(blob.Properties.Length);

                    transferContext.BlocksToTransfer = PrepareUploadDownloadQueue(sizeToDownload, blockSize,
                        ref numThreads, initialOffset);

                    transferContext.BlocksForFileIO = new ConcurrentDictionary<int, byte[]>();
                    for (int i = 0; i < transferContext.BlocksToTransfer.Count(); i++)
                    {
                        transferContext.BlocksForFileIO[i] = null;
                    }
                    transferContext.BlockSize = blockSize;
                    transferContext.CancellationToken = cancellationToken;
                    transferContext.BlobRequestOptions = blobRequestOptions;
                    transferContext.MemoryManager = MemoryManagerFactory.GetMemoryManager(blockSize);
                    transferContext.Client = client;
                    transferContext.RetryPolicy = retryPolicy;
                    transferContext.GetSharedAccessSignature = getSharedAccessSignature;
                    transferContext.ShouldDoFileIO = shouldDoFileIO;
                    transferContext.BufferStreams = new ConcurrentDictionary<byte[], MemoryStream>();
                    transferContext.ClientRequestId = DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture);

                    using (FileStream stream = new FileStream(
                        transferContext.LocalFilePath,
                        FileMode.OpenOrCreate,
                        FileAccess.Write,
                        FileShare.Read
                        ))
                    {
                        stream.SetLength(sizeToDownload);
                        RunDownloadLoop(transferContext, stream, numThreads);
                    }
                }
            }
            catch(Exception e)
            {
                //Add the exception to the exception list.
                transferContext.Exceptions.Add(e);
            }
            finally
            {
                 // We should to be able to releaseunusedbuffers if memorymanager was initialized by then
                if (transferContext.MemoryManager != null)
                {
                    transferContext.MemoryManager.ReleaseUnusedBuffers();
                }
                //TaskCompletedCallback should be called to populate exceptions if relevant and other eventargs for the user.
                    TaskCompletedCallback(
                        cancellationToken.IsCancellationRequested,
                        transferContext.Exceptions != null && transferContext.Exceptions.Count > 0
                            ? new AggregateException(transferContext.Exceptions)
                            : null,
                        BlobTransferType.Download,
                        localFile,
                        uri);
            }
        }