How to download a file to browser from Azure Blob Storage

While blob content may be streamed through a web server, and along to the end user via browser, this solution puts load on the web server, both cpu and NIC.

An alternative approach is to provide the end user with a uri to the desired blob to be downloaded, which they may click in the html content. e.g. https://myaccount.blob.core.windows.net/mycontainer/myblob.ext.

The issue with this is if the content is private, since a uri such as the one above won't work unless using public blobs. For this, you can create a Shared Access Signature (or server-stored Policy), which then results in a hashed querystring appended to the uri. This new uri would be valid for a given length of time (10 minutes, for example).

Here's a small example of creating an SAS for a blob:

var sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-5);
sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10);
sasConstraints.Permissions = SharedAccessBlobPermissions.Read;

var sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);

return blob.Uri + sasBlobToken;

Note that the start time is set to be a few minutes in the past. This is to deal with clock-drift. Here is the full tutorial I grabbed/modified this code sample from.

By using direct blob access, you will completely bypass your VM/web role instance/web site instance (reducing server load), and have your end-user pull blob content directly from blob storage. You can still use your web app to deal with permissioning, deciding which content to deliver, etc. But... this lets you direct-link to blob resources, rather than streaming them through your web server.


If you use ASP.NET (core), you can stream the content to the browser without saving the file on the server and using FileStreamResult which is IActionResult would be more elegant solution.

var stream = await blob.OpenReadAsync();
return File(stream, blob.Properties.ContentType, option);

Once the user clicks a file the server responds with this

var blob = container.GetBlobReferenceFromServer(option);

var memStream = new MemoryStream();
blob.DownloadToStream(memStream);

Response.ContentType = blob.Properties.ContentType;
Response.AddHeader("Content-Disposition", "Attachment;filename=" + option);
Response.AddHeader("Content-Length", blob.Properties.Length.ToString());
Response.BinaryWrite(memStream.ToArray());

HUGE thanks to Dhananjay Kumar for this solution