Upload to Azure Blob Storage with Angular

Stuart Tottle
5 min readMar 4, 2018

--

Upload multiple files to blob storage and report progress using Angular with a Shared Access Signature (SAS) token generated from your back-end.

Update 2019–11–05: I’ve created a new article that uses Angular & and the newer Azure Blob Storage NPM package @azure/storage-blob. You can see it here

We’ll go over

  • Creating an Angular project using the Angular-Cli
  • Creating an Angular service to upload a file to Blob Storage with tests
  • Update app component to upload files and display upload progress
  • Securing the upload to Blob Storage with a SAS token

Final code is here

Create the Angular solution

Use the Angular-Cli to create a new Angular project and the Blob Storage service.

npm install -g @angular/cling new stottle-angular-blob-storage-uploadcd ./stottle-angular-blob-storage-uploadng g service azure-storage/blobStorage -m app.module.ts

Add Azure Storage JS Library Files

Download the files from: https://aka.ms/downloadazurestoragejs

We are using version `2.10.100` for this example.

There are several files in the download but we just need to add the azure-storage.blob.js file to the assets directory in your Angular-Cli project. Also, add a reference to the script in angular.json

“scripts”: [ 
“./assets/azure-storage/azure-storage.blob.js”
]

Create the Blob Upload Service

We’ll show examples for

  1. Creating interfaces for the azure-storage.blob.js script
  2. Updating the blob-storage.service.ts to upload the files and report progress
  3. Creating a stub of azure-storage.blob.js script to mock the upload progress for our tests
  4. Updating blob-storage.service.spec.ts to use our stub and test the service

1. Interfaces

Create a file (eg azureStorage.ts) in the same directory as the blob storage service to contain the Interfaces for the azure-storage.blob.js script. There is also an azure-storage npm package with typings etc which I am sure could be used.

We also create an injection token on line 38 so we can create a stub for azure-storage.blob.js in our tests (example below).

2. Blob Storage Service

Update blob-storage.service.ts with the following

The only public method uploadToBlobStorage returns an observable of a number that represents the completed percent of the upload progress.

The implementation I am using it for requires a complete percentage of 100 so Iworked around this on line 55 as the progress could return 100 before the complete callback on line 44.

We also return a start value of 0 on line 48 so any subscriptions to the upload progress will have an initial value of 0 instead of waiting for spreed summary progress or complete callback to emit a value.

3. Create stub for testing

Create a file (eg blob-stroage-stub.ts) for the stub of the azure-storage.blob.js script. We use our interfaces created in step 1 and use rxjs to mock the upload progress. We also export an uploadProgressStub on line 5 to compare the progress emitted from our service to the current progress in the stub.

4. Test the service

Update blob-storage.service.spec.ts file to test our service. We provide our injection token on line 14 and set the value as our stub on line 15.

Create input in app component

Add aonFileChange method to app.component.ts to handle the change event of a file input and inject the BlobStorageService as a dependency.

On line 38 we

  1. Create an observable from our selected files to emit each file one at a time.
  2. Map the file to an observable of the upload progress. The uploadFile method uses the blob storage service to upload the file and return an observable of the upload progress.
  3. Combine all the mapped observable’s to return an observable with an array of items which represent our upload progress

Also update the template to include

  • a file input which triggers a function on change and include the multiple attribute to allow multiple files to be selected for upload.
  • the upload progress obserable

Update app.module

Use the injection token to provide the azure-storage.blob.js script and declare the script on line 7

Shared Access Signature (SAS) Token

We have hard coded the SAS token and location in the onFileChange method as I’m using the Azure Storage Emulator installed locally and I’ve generated the SAS Token using the Azure Storage Explorer (right click on the container to generate), but it would make much more sense to integrate with an API which requires authorisation to supply a

  • SAS Token with a limited life span
  • Url of the storage account “http://<accountname>.blob.core.windows.net”
  • Name of the container to which the file will be uploaded

Cors

Don’t forget to configure CORS in your emulator or the azure portal.

Conclusion

We could improve the solution by validating the file type, handling exceptions during the upload and include average upload speed as the `speedSummary` also returns other useful information which is available in their API docs

We could also add the response to the observable returned from the upload method rather than 100 to confirm the status of the upload.

We’re calling the done() method to let jasmine know the test has finished. We did try using fakeAsync, but ran into error stating Error: 1 timer(s) still in the queue. My brief research seemed to point to an issue with using interval in rxjs and i’m hoping anyone reading this article can explain to me why and if there is a better way to create the stub.

I also found another NPM package (angular-azure-blob-service) which worked well and uses the HttpClient in Angular to upload the file in blocks.

Links

--

--