I am attempting to download a file from Azure Storage in the form of an CloudBlockBlob
. I want to allow the user to select where to put the downloaded file, so I have written the following code to do this
[AllowAnonymous]
public async Task<ActionResult> DownloadFile(string displayName)
{
ApplicationUser user = null;
if (ModelState.IsValid)
{
user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
// Retrieve storage account and blob client.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.AppSettings["StorageConnectionString"]);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(
VisasysNET.Utilities.Constants.ContainerName);
// If the container does not exist, return error.
if (container.Exists())
{
foreach (IListBlobItem item in container.ListBlobs(null, false))
{
if (item.GetType() == typeof(CloudBlockBlob))
{
CloudBlockBlob blob = (CloudBlockBlob)item;
if (blob.Name.CompareNoCase(displayName))
{
using (Stream stream = new MemoryStream())
{
await blob.DownloadRangeToStreamAsync(stream, null, null);
return File(stream, displayName);
}
}
}
}
return RedirectToAction("Index", "Tools");
}
}
return new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable);
}
This idea was to return the FileStreamResult
and allow the browser to provide the "Save Dialog". However, when the controller posts to the view, I get an
Cannot access a closed Stream. Exception Details: System.ObjectDisposedException: Cannot access a closed Stream.
Now the problem is clear, however, how to circumvent it is not. I want to ensure the MemoryStream
is released and disposed as it is likely to hold data up to ~10M. How can I dispose the MemoryStream
but allow the FileStreamResult
to be passed back and used by the browser?
Thanks for your time.