title: azure blob storage async download with progress bar
body: <p>i am trying to get a COMPLETE example of downloading a file form Azure Blob Storage using the .DownloadToStreamAsync() method wired up to a progress bar.</p>
  
  <p>i've found references to old implementations of the azure storage sdk, but they dont compile with the newer sdk (that has implemented these async methods) or don't work with current nuget packages.</p>
  
  <p><a href="https://blogs.msdn.microsoft.com/avkashchauhan/2010/11/03/uploading-a-blob-to-azure-storage-with-progress-bar-and-variable-upload-block-size/" rel="noreferrer">https://blogs.msdn.microsoft.com/avkashchauhan/2010/11/03/uploading-a-blob-to-azure-storage-with-progress-bar-and-variable-upload-block-size/</a></p>
  
  <p><a href="https://blogs.msdn.microsoft.com/kwill/2013/03/05/asynchronous-parallel-blob-transfers-with-progress-change-notification-2-0/" rel="noreferrer">https://blogs.msdn.microsoft.com/kwill/2013/03/05/asynchronous-parallel-blob-transfers-with-progress-change-notification-2-0/</a></p>
  
  <p>i'm a newbie to async/await threading in .NET, and was wondering if someone could help me out with taking the below (in a windows form app) and showing how i can 'hook' into the progress of the file download... i see some examples dont use the .DownloadToStream method, and they instead download chunks of the blob file.. but i wondered since these new ...Async() methods exist in the newer Storage SDK's, if there was something smarter that could be done?</p>
  
  <p>So assuming the below is working (non async), what additionally would i have to do to use the blockBlob.DownloadToStream<strong>Async</strong>(fileStream); method, is this even the right use of this, and how can i get the progress?</p>
  
  <p>ideally i am after any way i can just hook the progress of the blob download so i can update a Windows Form UI on big downloads.. so if the below is not the right way, please enlighten me :)</p>
  
  <pre><code>// Retrieve storage account from connection string.
  CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
      CloudConfigurationManager.GetSetting("StorageConnectionString"));
  
  // Create the blob client.
  CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
  
  // Retrieve reference to a previously created container.
  CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
  
  // Retrieve reference to a blob named "photo1.jpg".
  CloudBlockBlob blockBlob = container.GetBlockBlobReference("photo1.jpg");
  
  // Save blob contents to a file.
  using (var fileStream = System.IO.File.OpenWrite(@"path\myfile"))
  {
      blockBlob.DownloadToStream(fileStream);
  }
  </code></pre>
  
  <hr>
  
  <p>Using the awesome suggested <a href="https://stackoverflow.com/questions/22763235/azure-download-blob-part">method</a> (downloading 1mb chunks) kindly  suggsted by <a href="https://stackoverflow.com/users/188096/gaurav-mantri">Gaurav</a>, i have implemented using a background worker to do the download so i can update the UI as i go.  </p>
  
  <p>The main part inside the do loop that downloads the range to a stream and then writes the stream to the file system I havent touched from the original example, but i have added code to update the worker progress and to listen for the worker cancellation (to abort the download).. not sure if this could be the issue?</p>
  
  <p>For completeness, below is everything inside the worker_DoWork method:</p>
  
  <pre><code>public void worker_DoWork(object sender, DoWorkEventArgs e)
      {
          object[] parameters = e.Argument as object[];
          string localFile = (string)parameters[0];
          string blobName = (string)parameters[1];
          string blobContainerName = (string)parameters[2];
          CloudBlobClient client = (CloudBlobClient)parameters[3];      
  
          try
          {
              int segmentSize = 1 * 1024 * 1024; //1 MB chunk
              var blobContainer = client.GetContainerReference(blobContainerName);
              var blob = blobContainer.GetBlockBlobReference(blobName);
              blob.FetchAttributes();
              blobLengthRemaining = blob.Properties.Length;
              blobLength = blob.Properties.Length;
              long startPosition = 0;
              do
              {
                  long blockSize = Math.Min(segmentSize, blobLengthRemaining);
                  byte[] blobContents = new byte[blockSize];
                  using (MemoryStream ms = new MemoryStream())
                  {
                      blob.DownloadRangeToStream(ms, startPosition, blockSize);
                      ms.Position = 0;
                      ms.Read(blobContents, 0, blobContents.Length);
                      using (FileStream fs = new FileStream(localFile, FileMode.OpenOrCreate))
                      {
                          fs.Position = startPosition;
                          fs.Write(blobContents, 0, blobContents.Length);
                      }
                  }
                  startPosition += blockSize;
                  blobLengthRemaining -= blockSize;
  
                  if (blobLength &gt; 0)
                  {
                      decimal totalSize = Convert.ToDecimal(blobLength);
                      decimal downloaded = totalSize - Convert.ToDecimal(blobLengthRemaining);
                      decimal blobPercent = (downloaded / totalSize) * 100;
                      worker.ReportProgress(Convert.ToInt32(blobPercent));
                  }
  
                  if (worker.CancellationPending)
                  {
                      e.Cancel = true;
                      blobDownloadCancelled = true;
                      return;
                  }
              }
              while (blobLengthRemaining &gt; 0);
          }
          catch (Exception ex)
          {
              MessageBox.Show(ex.Message);
          }
      }
  </code></pre>
  
  <p>This is working, but on bigger files (30mb for example), i sometimes am getting 'can't write to file as open in another process error...' and the process fails.. </p>