Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8

In this post, we will see how to upload, list, download, and delete files from Azure Blob Storage using ASP.NET Core Web API service and Angular 8 application.

Introduction

 
Blob Storage is a feature in Microsoft Azure that lets developers store unstructured data in Microsoft's cloud platform. This data can be accessed from anywhere in the world and can include audio, video, and text files. Blobs are grouped into "containers" that are tied to user accounts. Blobs can be manipulated with .NET or .NET Core code.
 
In this article, we will see how to create Azure Blob Storage and create services in ASP.NET Core Web API to upload, list, download, and delete files from Azure Blob Storage. We will create an Angular 8 application to perform these operations from the client side.
 

Create Blob storage in Azure portal

 
It is easy to create a blob storage in Azure portal. Choose “Storage account” and give the required information. Choose a unique name for the storage account.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Click the “Review + create” button to validate and then, click the “Create” button to proceed.
 
Currently, there are four types of services available in the storage account.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
We can choose “Blobs” and create a container to store our unstructured data.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
We can choose the access level as “Private” so that nobody will access without enough privileges. You can click “Access keys” tab and choose connection string and keep that in a secure place for future usage. We will use this connection string in our ASP.NET Core project later.
 

Create a Web API service in ASP.NET Core project

 
We can create a new ASP.NET Web API project in Visual Studio and create all services for file operations.
 
Please choose "API" template.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Our project will be ready in a few moments.
 
We can keep the blob storage connection string and container name in the appsettings.js file. We will fetch these values from the settings file using a configuration class file. We can create a config file “MyConfig.cs” to access these configuration values.
 
MyConfig.cs
  1. namespace BlobStorageASP.NETCore  
  2. {  
  3.     public class MyConfig  
  4.     {  
  5.         public string StorageConnection { getset; }  
  6.         public string Container { getset; }  
  7.     }  
  8. }  
I have created two properties for connection string and container name respectively inside this class file.
 
We can add storage connection string and container name in the appsettings.js file as well.
 
appsettings.js
  1. {  
  2.   "Logging": {  
  3.     "LogLevel": {  
  4.       "Default""Warning"  
  5.     }  
  6.   },  
  7.   "MyConfig": {  
  8.     "StorageConnection""DefaultEndpointsProtocol=https;AccountName=sarathstorageaccount;AccountKey=G176lDXKsN1joI6yL9G/JuC4MCMdMSZNEJBzIYZnhcQsjkRd8MCfoxREiqguuo5kON2BcIpSHXSqnVDZ9+7OAQ==;EndpointSuffix=core.windows.net",  
  9.     "Container""sarathcontainer"  
  10.   },  
  11.   "AllowedHosts""*"  
  12. }  
Modify the Startup.cs class with below changes. We have added dependency for MyConfig class. We have enabled CORS in this class too because we will consume these Web API services in Angular 8 application.
 
Startup.cs
  1. using Microsoft.AspNetCore.Builder;  
  2. using Microsoft.AspNetCore.Hosting;  
  3. using Microsoft.AspNetCore.Mvc;  
  4. using Microsoft.Extensions.Configuration;  
  5. using Microsoft.Extensions.DependencyInjection;  
  6.   
  7. namespace BlobStorageASP.NETCore  
  8. {  
  9.     public class Startup  
  10.     {  
  11.         public Startup(IConfiguration configuration)  
  12.         {  
  13.             Configuration = configuration;  
  14.         }  
  15.   
  16.         public IConfiguration Configuration { get; }  
  17.   
  18.         public void ConfigureServices(IServiceCollection services)  
  19.         {  
  20.             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);  
  21.             services.AddCors(c =>  
  22.             {  
  23.                 c.AddPolicy("AllowOrigin", options => options.WithOrigins("http://localhost:4200"));  
  24.             });  
  25.             services.Configure<MyConfig>(Configuration.GetSection("MyConfig"));  
  26.         }  
  27.   
  28.         public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  29.         {  
  30.             if (env.IsDevelopment())  
  31.             {  
  32.                 app.UseDeveloperExceptionPage();  
  33.             }  
  34.             app.UseCors(options => options.WithOrigins("http://localhost:4200"));  
  35.             app.UseMvc();  
  36.         }  
  37.     }  
  38. }  
We can create “BlobStorage” controller now. We will use scaffolding template for creating this Web API controller.
 
Right-click the Controllers folder and choose “Add New Scaffolded Item”.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Choose the “API” tab and select “API Controller with read/write actions” option.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Install “WindowsAzure.Storage” NuGet package in the project.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Copy the below code and paste inside this Controller class.
 
BlobStorageController.cs
  1. using Microsoft.AspNetCore.Http;  
  2. using Microsoft.AspNetCore.Mvc;  
  3. using Microsoft.Extensions.Options;  
  4. using Microsoft.WindowsAzure.Storage;  
  5. using Microsoft.WindowsAzure.Storage.Blob;  
  6. using System.Collections.Generic;  
  7. using System.IO;  
  8. using System.Threading.Tasks;  
  9.   
  10. namespace BlobStorageASP.NETCore.Controllers  
  11. {  
  12.     [Route("api/[controller]")]  
  13.     [ApiController]  
  14.     public class BlobStorageController : ControllerBase  
  15.     {  
  16.         private readonly IOptions<MyConfig> config;  
  17.   
  18.   
  19.         public BlobStorageController(IOptions<MyConfig> config)  
  20.         {  
  21.             this.config = config;  
  22.         }  
  23.   
  24.         [HttpGet("ListFiles")]  
  25.         public async Task<List<string>> ListFiles()  
  26.         {  
  27.             List<string> blobs = new List<string>();  
  28.             try  
  29.             {  
  30.                 if (CloudStorageAccount.TryParse(config.Value.StorageConnection, out CloudStorageAccount storageAccount))  
  31.                 {  
  32.                     CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();  
  33.   
  34.                     CloudBlobContainer container = blobClient.GetContainerReference(config.Value.Container);  
  35.   
  36.                     BlobResultSegment resultSegment = await container.ListBlobsSegmentedAsync(null);  
  37.                     foreach (IListBlobItem item in resultSegment.Results)  
  38.                     {  
  39.                         if (item.GetType() == typeof(CloudBlockBlob))  
  40.                         {  
  41.                             CloudBlockBlob blob = (CloudBlockBlob)item;  
  42.                             blobs.Add(blob.Name);  
  43.                         }  
  44.                         else if (item.GetType() == typeof(CloudPageBlob))  
  45.                         {  
  46.                             CloudPageBlob blob = (CloudPageBlob)item;  
  47.                             blobs.Add(blob.Name);  
  48.                         }  
  49.                         else if (item.GetType() == typeof(CloudBlobDirectory))  
  50.                         {  
  51.                             CloudBlobDirectory dir = (CloudBlobDirectory)item;  
  52.                             blobs.Add(dir.Uri.ToString());  
  53.                         }  
  54.                     }  
  55.                 }  
  56.             }  
  57.             catch  
  58.             {  
  59.             }  
  60.             return blobs;  
  61.         }  
  62.   
  63.         [HttpPost("InsertFile")]  
  64.         public async Task<bool> InsertFile(IFormFile asset)  
  65.         {  
  66.             try  
  67.             {  
  68.                 if (CloudStorageAccount.TryParse(config.Value.StorageConnection, out CloudStorageAccount storageAccount))  
  69.                 {  
  70.                     CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();  
  71.   
  72.                     CloudBlobContainer container = blobClient.GetContainerReference(config.Value.Container);  
  73.   
  74.                     CloudBlockBlob blockBlob = container.GetBlockBlobReference(asset.FileName);  
  75.   
  76.                     await blockBlob.UploadFromStreamAsync(asset.OpenReadStream());  
  77.   
  78.                     return true;  
  79.                 }  
  80.                 else  
  81.                 {  
  82.                     return false;  
  83.                 }  
  84.             }  
  85.             catch  
  86.             {  
  87.                 return false;  
  88.             }  
  89.         }  
  90.   
  91.         [HttpGet("DownloadFile/{fileName}")]  
  92.         public async Task<IActionResult> DownloadFile(string fileName)  
  93.         {  
  94.             MemoryStream ms = new MemoryStream();  
  95.             if (CloudStorageAccount.TryParse(config.Value.StorageConnection, out CloudStorageAccount storageAccount))  
  96.             {  
  97.                 CloudBlobClient BlobClient = storageAccount.CreateCloudBlobClient();  
  98.                 CloudBlobContainer container = BlobClient.GetContainerReference(config.Value.Container);  
  99.   
  100.                 if (await container.ExistsAsync())  
  101.                 {  
  102.                     CloudBlob file = container.GetBlobReference(fileName);  
  103.   
  104.                     if (await file.ExistsAsync())  
  105.                     {  
  106.                         await file.DownloadToStreamAsync(ms);  
  107.                         Stream blobStream = file.OpenReadAsync().Result;  
  108.                         return File(blobStream, file.Properties.ContentType, file.Name);  
  109.                     }  
  110.                     else  
  111.                     {  
  112.                         return Content("File does not exist");  
  113.                     }  
  114.                 }  
  115.                 else  
  116.                 {  
  117.                     return Content("Container does not exist");  
  118.                 }  
  119.             }  
  120.             else  
  121.             {  
  122.                 return Content("Error opening storage");  
  123.             }  
  124.         }  
  125.   
  126.   
  127.         [Route("DeleteFile/{fileName}")]  
  128.         [HttpGet]  
  129.         public async Task<bool> DeleteFile(string fileName)  
  130.         {  
  131.             try  
  132.             {  
  133.                 if (CloudStorageAccount.TryParse(config.Value.StorageConnection, out CloudStorageAccount storageAccount))  
  134.                 {  
  135.                     CloudBlobClient BlobClient = storageAccount.CreateCloudBlobClient();  
  136.                     CloudBlobContainer container = BlobClient.GetContainerReference(config.Value.Container);  
  137.   
  138.                     if (await container.ExistsAsync())  
  139.                     {  
  140.                         CloudBlob file = container.GetBlobReference(fileName);  
  141.   
  142.                         if (await file.ExistsAsync())  
  143.                         {  
  144.                             await file.DeleteAsync();  
  145.                         }  
  146.                     }  
  147.                 }  
  148.                 return true;  
  149.             }  
  150.             catch  
  151.             {  
  152.                 return false;  
  153.             }  
  154.         }  
  155.     }  
  156. }  
I have added the code for uploading, listing, downloading, and deleting files from Azure Blob Storage. All the code is self-explanatory.
 
We have completed the API project coding part. We can check these services using Postman or any other tools.
 

Create an Angular 8 client application using CLI

 
Create a new Angular 8 application using the below CLI command.
 
ng new BlobStorageAngular8
 
We need “bootstrap”, “font-awesome", and “file-save” libraries in this project. We can install these libraries one by one.
 
We can import “bootstrap” and “font-awesome” libraries inside the style.css class in the root folder of “src” folder. This way, we can use these libraries in the entire project without further references.
 
style.css
  1. /* You can add global styles to this file, and also import other style files */  
  2. @import "~bootstrap/dist/css/bootstrap.css";  
  3. @import "~font-awesome/css/font-awesome.css";  
Let us add “HttpClientModule” and “FormsModule” in app.module.ts file. We will use both these modules in our project.
 
app.module.ts
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { AppComponent } from './app.component';  
  4.   
  5. import { HttpClientModule } from '@angular/common/http';   
  6. import { FormsModule } from '@angular/forms';  
  7.   
  8. @NgModule({  
  9.   declarations: [  
  10.     AppComponent  
  11.   ],  
  12.   imports: [  
  13.     BrowserModule,  
  14.     HttpClientModule,  
  15.     FormsModule  
  16.   ],  
  17.   providers: [],  
  18.   bootstrap: [AppComponent]  
  19. })  
  20. export class AppModule { }  
We can modify the app.component.ts component file with the below code.
 
app.component.ts
  1. import { Component, OnInit } from '@angular/core';  
  2. import { HttpClient } from '@angular/common/http';  
  3. import { saveAs } from 'file-saver';  
  4. declare var require: any;  
  5.   
  6. @Component({  
  7.   selector: 'app-root',  
  8.   templateUrl: './app.component.html',  
  9.   styleUrls: ['./app.component.css']  
  10. })  
  11. export class AppComponent implements OnInit {  
  12.   constructor(private http: HttpClient) { }  
  13.   files: string[] = [];  
  14.   fileToUpload: FormData;  
  15.   fileUpload: any;  
  16.   fileUpoadInitiated: boolean;  
  17.   fileDownloadInitiated: boolean;  
  18.   private baseUrl = 'http://localhost:4000/api/blobstorage';  
  19.   
  20.   ngOnInit(): void {  
  21.     this.showBlobs();  
  22.   }  
  23.   
  24.   showBlobs() {  
  25.     this.http.get<string[]>(this.baseUrl + '/listfiles').subscribe(result => {  
  26.       this.files = result;  
  27.     }, error => console.error(error));  
  28.   }  
  29.   
  30.   addFile() {  
  31.     if (!this.fileUpoadInitiated) {  
  32.       document.getElementById('fileUpload').click();  
  33.     }  
  34.   }  
  35.   handleFileInput(files: any) {  
  36.     let formData: FormData = new FormData();  
  37.     formData.append("asset", files[0], files[0].name);  
  38.     this.fileToUpload = formData;  
  39.     this.onUploadFiles();  
  40.   }  
  41.   
  42.   onUploadFiles() {  
  43.     if (this.fileUpoadInitiated) {  
  44.       return;  
  45.     }  
  46.     this.fileUpoadInitiated = true;  
  47.     if (this.fileToUpload == undefined) {  
  48.       this.fileUpoadInitiated = false;  
  49.       return false;  
  50.     }  
  51.     else {  
  52.       return this.http.post(this.baseUrl + '/insertfile'this.fileToUpload)  
  53.         .subscribe((response: any) => {  
  54.           this.fileUpoadInitiated = false;  
  55.           this.fileUpload = '';  
  56.           if (response == true) {  
  57.             this.showBlobs();  
  58.           }  
  59.           else {  
  60.             alert('Error occured!');  
  61.             this.fileUpoadInitiated = false;  
  62.           }  
  63.         },  
  64.           err => console.log(err),  
  65.         );  
  66.   
  67.     }  
  68.   }  
  69.   downloadFile(fileName: string) {  
  70.     this.fileDownloadInitiated = true;  
  71.     return this.http.get(this.baseUrl + '/downloadfile/' + fileName, { responseType: "blob" })  
  72.       .subscribe((result: any) => {  
  73.         if (result.type != 'text/plain') {  
  74.           var blob = new Blob([result]);  
  75.           let saveAs = require('file-saver');  
  76.           let file = fileName;  
  77.           saveAs(blob, file);  
  78.           this.fileDownloadInitiated = false;  
  79.         }  
  80.         else {  
  81.           this.fileDownloadInitiated = false;  
  82.           alert('File not found in Blob!');  
  83.         }  
  84.       }  
  85.       );  
  86.   }  
  87.   deleteFile(fileName: string) {  
  88.     var del = confirm('Are you sure want to delete this file');  
  89.     if (!del) return;  
  90.     this.http.get(this.baseUrl + '/deletefile/' + fileName).subscribe(result => {  
  91.       if (result != null) {  
  92.         this.showBlobs();  
  93.       }  
  94.     }, error => console.error(error));  
  95.   }  
  96. }  
We have added all the logic for file operations with Blob Storage in this component.
 
Modify the corresponding HTML and CSS files for this component as well.
 
app.component.html
  1. <div style="text-align:center; margin-top: 20px;">  
  2.   <h4>  
  3.     Upload, Download and Delete Blob Files using ASP.NET Core and Angular 8  
  4.   </h4>  
  5. </div>  
  6.   
  7. <div class="blobstorage-section">  
  8.   <i class="fa fa-plus fa-2x" style="cursor: pointer; color: darkslateblue;" (click)="addFile()"></i>  Add new files to Blob  
  9.   <input style="display: none;" type="file" id="fileUpload" #selectedFile [(ngModel)]="fileUpload" (click)="selectedFile.value = null" value="" (change)="handleFileInput($event.target.files)" />  
  10.   <table style="margin-top: 20px;">  
  11.     <tr>  
  12.       <th class="column1">Uploaded Files</th>  
  13.       <th class="column2" style="text-align:center;">Download</th>  
  14.       <th class="column3" style="text-align:center;">Delete</th>  
  15.     </tr>  
  16.     <tr *ngFor="let file of files">  
  17.       <td class="column1">{{file}}</td>  
  18.       <td class="column2" style="text-align:center;cursor: pointer;" (click)="downloadFile(file)"><i class="fa fa-download"></i></td>  
  19.       <td class="column3" style="text-align:center;" (click)="deleteFile(file)">  
  20.         <img alt="Group Audit" src="../assets/icon-download.png" />  
  21.       </td>  
  22.     </tr>  
  23.   </table>  
  24. </div>  
app.component.css
  1. .blobstorage-section {  
  2.     font-family: Calibri;  
  3.     box-shadow: 0 1px 4px 0 #9b9b9b;  
  4.     background-color#ffffff;  
  5.     marginauto;  
  6.     margin-top50px;  
  7.     padding30px;  
  8.     width50%;  
  9. }  
  10.   
  11. .column1{  
  12.     width:450px;  
  13. }  
  14. .column2{  
  15.     width:100px;  
  16. }  
  17. .column3{  
  18.     width:100px;  
  19. }  
  20. .blobstorage-section th {  
  21.     font-family: Calibri;  
  22.     font-size14px;  
  23.     font-weightbold;  
  24.     font-stylenormal;  
  25.     font-stretchnormal;  
  26.     line-height1.57;  
  27.     letter-spacingnormal;  
  28.     color#333333;  
  29.     border-right1px solid #d7d7d7;  
  30.     border-bottom1px solid #d7d7d7;  
  31. }  
  32.   
  33. .blobstorage-section th i {   
  34.     font-family: Calibri;  
  35.     font-size16px;  
  36. }  
  37.   
  38. .blobstorage-section tbody tr td {  
  39.     border-right1px solid #d7d7d7;  
  40.     border-bottom1px solid #d7d7d7;  
  41. }  
  42.   
  43. .blobstorage-section tbody tr td a {  
  44.     font-family: Calibri;  
  45.     font-size15px;  
  46.     font-weightnormal;  
  47.     font-stylenormal;  
  48.     font-stretchnormal;  
  49.     line-height1.2;  
  50.     letter-spacingnormal;  
  51.     color#0091da;  
  52.     text-decorationunderline;  
  53. }  
  54.   
  55. .blobstorage-section tr td img:hover {  
  56.     cursorpointer;  
  57. }  
We have completed the entire project. Run both, ASP.NET Core project and Angular project, now.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
Click the (+) button to add new files.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 
You can download/delete these files using corresponding buttons in the grid.
 
Upload, Download, And Delete Blob Files Using ASP.NET Core And Angular 8
 

Conclusion

 
In this post, we have seen how to upload, list, download and delete files from Azure Blob storage using ASP.NET Core API project and we have consumed these services in an Angular 8 client project. You can download the source code and check from your side. Please feel free to contact me with your valuable comments on this article.