Upload to Azure Blob Storage with Angular
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
- Creating interfaces for the
azure-storage.blob.js
script - Updating the
blob-storage.service.ts
to upload the files and report progress - Creating a stub of
azure-storage.blob.js
script to mock the upload progress for our tests - 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
- Create an observable from our selected files to emit each file one at a time.
- 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.
- 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.