Downloading/streaming Azure Storage private container blobs to AngularJS through .net WebAPI

When our Azure storage contains files that are meant to be publically accessible, it’s pretty trivial to deliver them to the end-user. We can either embed such items (e.g. images) or simply add links which point to them (e.g. pdfs) because Azure provides direct links to them. But what happens when these files contain sensitive data that is not meant for just anyone? Perhaps some kind of reports?

Well, it gets a bit more complicated.. Since these files don’t have publically accessible URI’s any more, there are several steps which we need to go through:

  • Authenticate against Azure using SDK
  • Load the file into MemoryStream
  • Deliver the stream to the client (browser)
  • Convert the byte array into an actual file on the client-side and simulate “downloading”

Since we’ll need more than just the MemoryStream, we’ll wrap it together with the file metadata into a model object.

We will use AzureProvider class to authenticate against Azure, download the file from Azure and to create the model object.

Our actual controller will inherit from this BaseApi class which contains a custom IHttpActionResult method which we can name AzureBlobOk. This is something pretty reusable so it’s good to have it at hand in your base class. What it does is it sets up all the content headers and it attaches the stream as the response content payload . It also returns HTTP status 200 which means OK – everything went fine.

The actual controller is pretty simple..

On the client side, we’ll need the following service to actually convert the byte array that we got from the API into something meaningful. I tried various approaches, but in the end decided to use FileSaver.js which “implements the HTML5 W3C saveAs() FileSaver interface in browsers that do not natively support it”. What it will do is turn the byte array into an actual file and prompt the user to download it.

This service can easily be consumed by injecting it into your AngularJS controllers and calling the .getBlob() function which will do all the heavy lifting for you.

Hope this helped, enjoy! :)