title: Real World Async and Await Code Example
body: <p>I have been looking everywhere to find good real world examples of the new Async and Await features in .net 4.5. I have come up with the following code to download a list of files and limit the number of concurrent downloads. I would appreciate any best practices or ways to improve/optimize this code.</p>
  
  <p>We are calling the below code using the following statement. </p>
  
  <pre><code>await this.asyncDownloadManager.DownloadFiles(this.applicationShellViewModel.StartupAudioFiles, this.applicationShellViewModel.SecurityCookie, securityCookieDomain).ConfigureAwait(false);
  </code></pre>
  
  <p>We are then using events to add the downloaded files to an observablecollection (new thread safe version in .net 4.5)  on the ViewModel.</p>
  
  <pre><code>public class AsyncDownloadManager
      {
          public event EventHandler&lt;DownloadedEventArgs&gt; FileDownloaded;
  
          public async Task DownloadFiles(string[] fileIds, string securityCookieString, string securityCookieDomain)
            {
              List&lt;Task&gt; allTasks = new List&lt;Task&gt;();
              //Limits Concurrent Downloads 
              SemaphoreSlim throttler = new SemaphoreSlim(initialCount: Properties.Settings.Default.maxConcurrentDownloads);
  
              var urls = CreateUrls(fileIds);
  
              foreach (var url in urls)   
              {  
                  await throttler.WaitAsync();
                  allTasks.Add(Task.Run(async () =&gt; 
                  {
                      try
                      {
                          HttpClientHandler httpClientHandler = new HttpClientHandler();
                          if (!string.IsNullOrEmpty(securityCookieString))
                          {
                              Cookie securityCookie;
                              securityCookie = new Cookie(FormsAuthentication.FormsCookieName, securityCookieString);
                              securityCookie.Domain = securityCookieDomain;
                              httpClientHandler.CookieContainer.Add(securityCookie);    
                          }                     
  
                          await DownloadFile(url, httpClientHandler).ConfigureAwait(false);
                      }
                      finally
                      {
                          throttler.Release();
                      }
                  }));
              }
              await Task.WhenAll(allTasks).ConfigureAwait(false);
          }
  
          async Task DownloadFile(string url, HttpClientHandler clientHandler)
          {
              HttpClient client = new HttpClient(clientHandler);
              DownloadedFile downloadedFile = new DownloadedFile();
  
              try
              {
                  HttpResponseMessage responseMessage = await client.GetAsync(url).ConfigureAwait(false);
                  var byteArray = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
  
                  if (responseMessage.Content.Headers.ContentDisposition != null)
                  {
                      downloadedFile.FileName = Path.Combine(Properties.Settings.Default.workingDirectory, responseMessage.Content.Headers.ContentDisposition.FileName);
                  }
                  else
                  {
                      return;
                  }
  
                  if (!Directory.Exists(Properties.Settings.Default.workingDirectory))   
                  {
                      Directory.CreateDirectory(Properties.Settings.Default.workingDirectory);
                  }
                  using (FileStream filestream = new FileStream(downloadedFile.FileName, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                  {
                      await filestream.WriteAsync(byteArray, 0, byteArray.Length);
                  }
              }
              catch(Exception ex)
              {    
                  return; 
              }
              OnFileDownloaded(downloadedFile);
          }
  
          private void OnFileDownloaded(DownloadedFile downloadedFile)
          {    
              if (this.FileDownloaded != null)
              {
                  this.FileDownloaded(this, new DownloadedEventArgs(downloadedFile));
              }
          }    
  
      public class DownloadedEventArgs : EventArgs
      {
          public DownloadedEventArgs(DownloadedFile downloadedFile)
          {   
              DownloadedFile = downloadedFile;
          }
  
          public DownloadedFile DownloadedFile { get; set; }
      }
  </code></pre>
  
  <p>After suggestion by Svick - The following are direct questions:</p>
  
  <ol>
  <li>What is the affect of embedding Async / Await in other Async / Await methods? (Write filestream to disk inside an Async / Await method.</li>
  <li>Should a httpclient be used for each separate task or should they share a singe one?</li>
  <li>Are events a good way to "send" the downloaded file reference to the viewmodel?
  [I will also post in codereview]</li>
  </ol>