One of the main components of the Digital transformation journey is storing and managing files and documents securely. Most of the applications require some features related to file upload and managing. We generally look for secure, durable, scalable, and high availability. Moreover, storing documents requires high storage space and a highly secure platform.

Uploading files or attachments is one of the common requirements for any application. Azure storage is one of the most efficient cloud storage with all the necessary features, securities, and compliance.

Azure Storage, a platform owned by Microsoft, is a contemporary cloud storage solution for almost every case scenario that is highly secure, scalable, durable, and easy to manage.

In this article, we will learn about Azure Storage and its data services. Additionally, we will create an azure storage data service with an example of Azure Blobs. Furthermore, we will upload, delete, and view files to Azure Blobs with Blazor application in .NET 7. The outline of this article are follows:

  •         What is Azure Storage
  •         What are the Azure Storage data services?
  •         How to create an Azure Storage Account?
  •         .NET Generally available
  •         What is a Blazor Web App?
  •         Create a Blazor Web App with .NET 7
  •         Upload, delete and view files in Azure Blobs using a Blazor App in .NET 7

You can find a complete Solution on GitHub, Click Here.

Azure Storage

Azure Storage is a modern cloud storage solution owned by Microsoft, for almost every data storage scenario that is highly secure, scalable, durable, and easy to manage. It is well managed for hardware, updates, critical issues, high availability and is accessible from any part of the globe. Furthermore, the Azure UI is user-friendly, and we can create the services/objects effortlessly with all the configuration features. Additionally, Azure Storage provides all the necessary client libraries/SDK in .NET, Python, JavaScript, Java C++, PHP, Node.js, Ruby, Go, therefore developers can simply implement in their applications using the programming language of their choice. We can even access the storage objects via HTTP, HTTPS or REST API. Azure CLI or Azure PowerShell can be used by IT professionals to create scripts for those services and configuration tasks.

Let’s discuss Azure Storage Data Services.

Azure Storage Data Services

Azure storage consists of 5 data services, as portrayed in the above diagram.

Azure Blob Storage

Azure Blob Storage is a type of Azure Storage for storing massively scalable objects that are, particularly unstructured data such as text or binary data. It is used to store and access those unstructured data at a massive scale of block blobs. You can access the blob files via any applications using client libraries for multiple programming languages like .NET, Python, Java, Node.js, Ruby and PHP. Furthermore, we can use HTTP service access globally with secure access.

Scenarios to Use Azure Blob Storage

  • Storing files and document form various applications
  • Storing large file
  • Streaming video and audio files
  • Accessing files and images from browser
  • Storing file for backup, archiving, disaster recovery
  • Access file from anywhere globally via HTTP service
  • Distributed access to files and documents
  • Secure Access

​Azure Files

Azure Files Service provides a fully managed serverless file sharing option in the cloud via the industry-standard SMB and NFS protocols. Azure files enables us to build a truly hybrid file sharing environment from anywhere by mounting it concurrently from on premises and cloud.  

​To know more details: https://azure.microsoft.com/en-us/products/storage/files/

Azure Tables

This storage table is used for storing large amount of non-relational structured or semi-structured data, i.e. NoSQL key-value for speedy development. This is highly efficient for the applications that require flexible data schema and massive data in the cloud.

https://learn.microsoft.com/en-us/azure/storage/tables/table-storage-overview

Azure Queues

This storage service is used for storing and queuing a large number of messages that can be accessed from any part of the globe via authenticated HTTP service calls. ​The Azure Queue storage provides messaging among the applications in the cloud and can be used in any programming language.         

https://learn.microsoft.com/en-us/azure/storage/queues/storage-queues-introduction

Know more about other storage services in more detail.

https://learn.microsoft.com/en-us/azure/storage/common/storage-introduction

In this write-up, we will learn to use azure storage to upload, view and delete files using Blazor Web Apps. We will upload and view files in Azure Storage using Blazor web app with .NET 7.

Let’s commence 😊.

Prerequisites

  • Visual Studio 2022
  • .NET 7
  • Azure Subscription (You can create trial subscription)
  • C# Knowledge

We will use Blazer Server with .NET 7 and Azure Blob Storage.

Create Azure Storage Account

Azure storage account provides a unique namespace in the cloud for our azure storage that contains all the azure data storage components including Blob storage, Azure Files, Azure Tables, Azure Queues, and disks and can be accessible through authenticate HTTP(S) calls.

https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview

We will login to the Azure portal and search for a Storage Account.

Click Create for Storage Account.


We provide basic inputs for the storage account. 

Choose your Subscription, Resource Group, Storage Account Name, Performance and Redundancy.

You can choose the nearest region from your location. Furthermore, we will determine the premium performance block blobs, file shares, or page blobs for the storage account.

Importantly, the data of the storage account is always duplicated to safeguard high availability and durability. We can decide redundancy of our choice. 

For this article, I will go with low-cost option – Locally-redundant storage LRS.

Next, we will complete the advance options as portrayed.

Security Section

Data Lake Storage Gen2

Blog Storage and Azure Files

Next, we will move to the networking section.

Similarly, we will provide the data projection settings.

Encryption section

Add your tags, review, and then create the storage account.

It will take a few seconds to create the storage account.

Finally, the storage account is created as shown below.

Add Container

We will a container for uploading our files. 

Now we are ready to use this container of this Azure Storage account in Blazor Application. However, we need access keys or connection strings to upload files, which can be Azure Blade Access Keys as shown below.

.NET 7 SDK

We can use any version of Visual Studio 2022, and we can download from this link. You can use the community version, which is free. Additionally, you can download .NET 7 SDK for free from this official site. In my case, I am using Visual Studio 2022 Professional, however, the steps and interfaces are the same for other versions.

Let’s commence.

We will start with the installation .NET 7 SDK for Windows. 

Create a Web App with Blazor Server

Blazor server runs as an implementation of server side as a part of ASP.NET core app where UI events, button clicks, UI updates and interactions are communicated over SignalR connection. In this approach, the UI is generated on a web server and is transmitted to the visitor’s browser upon request. This two-way interaction occurs using SignalR and a web sockets connection. Any change in DOM content is generated from web server and update in automatically via SignalR with Blazor Server framework. This Blazor type has direct access to server and network resources since app is executed in server side. Let’s open a Visual Studio and create a new project. We will use the Blazor Server App project template.

To know more about Blazor Web Development, click here.

To learn to develop a Blazor Application, click here.

We will provide a project name and location for the solution.

​On the next screen, we will get options to choose .Net framework, Authentication type and a couple options for the project.

After installation of .NET 7 SDK, we will have an option to choose .NET 7 in the framework. We will select the .NET 7 framework and proceed. To keep it simple, we will keep other options default.

We have successfully created a Blazor server web application with .NET 7. We will build and run the solution.

This is how we can create a Blazor server app.

Upload and Delete Files in Azure Blob Storage Using Blazor App with .NET 7

In this section, I will write a complete project to upload and delete files in Azure Blob Storage using Blazor app in the above solution.

Firstly, we will a NuGet package named Azure.Storage.Blobs as shown below.

We will begin by creating a service class for Azure Blob Storage under a folder name Services. We will add an IBlobStorageService named interface class as shown. 

Define an upload and delete method of the file as shown below.

Code for IBlobStorageService.cs

namespace RijsatFileUploadAzureStorage.Services;
public interface IBlobStorageService
{
    Task<string> UploadFileToBlobAsync(string strFileName, string contecntType, Stream fileStream);
    Task<bool> DeleteFileToBlobAsync(string strFileName);
}

Again, add a BlobStorageService named implementation class for the above interface under the same services folder.

The structure will be as shown below.

Add a constructor and inject application Configuration.

Code

private readonly IConfiguration _configuration;
private readonly ILogger<BlobStorageService> _logger;
public BlobStorageService(IConfiguration configuration, ILogger<BlobStorageService> logger)
{
        _configuration = configuration;   
        _logger = logger;
}

We will add the connection sting of Storage account into appsetting.json as shown below:

Likewise, we use this connection string in our BlobStorageService service class.

We will also define our container for this blob storage. Our container name is rijsatdemo which we created during the storage account.

Function for File Upload

Please the references as shown.

Code for Upload Function

public async Task<string> UploadFileToBlobAsync(string strFileName, string contecntType, Stream fileStream)
    {
        try
        {
            var container = new BlobContainerClient(blobStorageconnection, blobContainerName);
            var createResponse = await container.CreateIfNotExistsAsync();
            if (createResponse != null && createResponse.GetRawResponse().Status == 201)
                await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
            var blob = container.GetBlobClient(strFileName);
            await blob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
            await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = contecntType });
            var urlString = blob.Uri.ToString();
            return urlString;
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex.ToString());
            throw;
        }
    }

Similarly, the code for deleting file method.

public async Task<bool> DeleteFileToBlobAsync(string strFileName)
    {
        try
        {
            var container = new BlobContainerClient(blobStorageconnection, blobContainerName);
            var createResponse = await container.CreateIfNotExistsAsync();
            if (createResponse != null && createResponse.GetRawResponse().Status == 201)
                await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
            var blob = container.GetBlobClient(strFileName);
            await blob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
            return true;
        }
        catch (Exception ex )
        {
            _logger?.LogError(ex.ToString());
            throw;
        }
    }

Overall, the BlobStorageService class be as shown below.

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.Extensions.Logging;
using System.Reflection.Metadata.Ecma335;

namespace RijsatFileUploadAzureStorage.Services;
public class BlobStorageService : IBlobStorageService
{
    private readonly IConfiguration _configuration;
    private readonly ILogger<BlobStorageService> _logger;
    string blobStorageconnection = string.Empty;
    private string blobContainerName = "rijsatdemo";
    public BlobStorageService(IConfiguration configuration, ILogger<BlobStorageService> logger)
    {
        _configuration = configuration;   
        _logger = logger;
        blobStorageconnection = _configuration.GetConnectionString("AzureStorageAccount");
    }
    public async Task<string> UploadFileToBlobAsync(string strFileName, string contecntType, Stream fileStream)
    {
        try
        {
            var container = new BlobContainerClient(blobStorageconnection, blobContainerName);
            var createResponse = await container.CreateIfNotExistsAsync();
            if (createResponse != null && createResponse.GetRawResponse().Status == 201)
                await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
            var blob = container.GetBlobClient(strFileName);
            await blob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
            await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = contecntType });
            var urlString = blob.Uri.ToString();
            return urlString;
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex.ToString());
            throw;
        }
    }
    public async Task<bool> DeleteFileToBlobAsync(string strFileName)
    {
        try
        {
            var container = new BlobContainerClient(blobStorageconnection, blobContainerName);
            var createResponse = await container.CreateIfNotExistsAsync();
            if (createResponse != null && createResponse.GetRawResponse().Status == 201)
                await container.SetAccessPolicyAsync(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
            var blob = container.GetBlobClient(strFileName);
            await blob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots);
            return true;
        }
        catch (Exception ex )
        {
            _logger?.LogError(ex.ToString());
            throw;
        }
    }
}

We will add a dependency injection service to the container in the program.cs file.

builder.Services.AddScoped<IBlobStorageService, BlobStorageService>();

Add a view model or Data transfer object of file upload into services folder as shown.

Code for the FileUploadViewModel.cs

namespace RijsatFileUploadAzureStorage.Services.Dto
{
    public class FileUploadViewModel
    {
        public string FileName { get; set; }
        public string FileStorageUrl { get; set; }
        public string ContentType { get; set; }
    }
}

Now we will move to the Blazor Component for the uploading section in the Index.razor component file.

Add a file upload section into Index component. Replace Index with below code.

<h4>File Upload (Azure Blob Storage)</h4>
<div class="row">
    <div class="col-sm-6">
        <label>
            <InputFile class="form-control" disabled="@fileLoading" OnChange="@OnInputFileChange" single />
        </label>
        @if (fileLoading)
        {
            <i class="fa fa-refresh"></i> <span>Loading...</span>
        }
    </div>
    <div class="col-sm-2">
        <button type="button" disabled="@fileLoading" class="btn btn-primary" @onclick="OnUploadSubmit">
            Upload File
        </button>
    </div>
</div>

Then, I will add a table to show the list of uploaded files.

<div class="row">
    @if (fileUploadViewModels.Count > 0)
    {
        <table class="table table-responsive table-bordered">
            <thead class="text-primary">
                <tr>
                    <th>File</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var attachment in fileUploadViewModels)
                {

                    <tr>
                        <td>
                            <a class="text-primary"><i class="fa-solid fa-paperclip"></i> @attachment.FileName</a>
                        </td>                      
                       
                            <td>
                            <span class="oi oi-delete" aria-hidden="true" @onclick="() => OnFileDeleteClick(attachment)"></span>
                            </td>
                    </tr>
                }
            </tbody>
        </table>
    }
    else
    {
        <div class="alert alert-info">
            <strong>No Files!</strong>
        </div>
    }
</div>

We will add the code part for uploading and deleting in index.razor component.

@code {
    private string warninngMessage = "";
    private string displayMessage = "";
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool fileLoading;
    string Message = "No file(s) selected";
    IReadOnlyList<IBrowserFile> selectedFiles;
    private List<FileUploadViewModel> fileUploadViewModels = new();
    private void OnInputFileChange(InputFileChangeEventArgs e)
    {
        selectedFiles = e.GetMultipleFiles();
        Message = $"{selectedFiles.Count} file(s) selected";
        this.StateHasChanged();
    }
    private async void OnUploadSubmit()
    {
        fileLoading = true;
        foreach (var file in selectedFiles)
        {
            try
            {
                var trustedFileNameForFileStorage = file.Name;
                var blobUrl = await blobStorageService.UploadFileToBlobAsync(trustedFileNameForFileStorage, file.ContentType, file.OpenReadStream(20971520));
                if (blobUrl != null)
                {
                    FileUploadViewModel fileUploadViewModel = new FileUploadViewModel()
                        {
                            FileName = trustedFileNameForFileStorage,
                            FileStorageUrl = blobUrl,
                            ContentType = file.ContentType,
                        };

                    fileUploadViewModels.Add(fileUploadViewModel);
                    displayMessage = trustedFileNameForFileStorage + " Uploaded!!";
                }
                else
                    warninngMessage = "File Upload failed, Please try again!!";

            }
            catch (Exception ex)
            {
                warninngMessage = "File Upload failed, Please try again!!";
            }
        }

        fileLoading = false;
        this.StateHasChanged();
    }

    private async void OnFileDeleteClick(FileUploadViewModel attachment)
    {
        try
        {
            var deleteResponse = await blobStorageService.DeleteFileToBlobAsync(attachment.FileName);
            if (deleteResponse)
            {
                fileUploadViewModels.Remove(attachment);
                displayMessage = attachment.FileName + " Deleted!!";
            }
            
        }
        catch (Exception)
        {
            warninngMessage = "Something went wrong! Please try again.";
        }
        this.StateHasChanged();
    }

}

In the above code, we have OnUploadSubmit() and OnFileDeleteClick().

Complete Index.razor component code.

@page "/"
@using RijsatFileUploadAzureStorage.Services;
@using RijsatFileUploadAzureStorage.Services.Dto;
@inject IBlobStorageService blobStorageService

<PageTitle>Index</PageTitle>
@if (warninngMessage.Length > 0)
{
    <div class="alert alert-warning">
        <strong>Warning!</strong> @warninngMessage.
    </div>
}

<h4>File Upload (Azure Blob Storage)</h4>
<div class="row">
    <div class="col-sm-6">
        <label>
            <InputFile class="form-control" disabled="@fileLoading" OnChange="@OnInputFileChange" single />
        </label>
        @if (fileLoading)
        {
            <i class="fa fa-refresh"></i> <span>Loading...</span>
        }
    </div>
    <div class="col-sm-2">
        <button type="button" disabled="@fileLoading" class="btn btn-primary" @onclick="OnUploadSubmit">
            Upload File
        </button>
    </div>
</div>
@if (displayMessage.Length > 0)
{
    <div class="alert alert-success">
        <strong>Success!</strong> @displayMessage.
    </div>
}
<br />
<div class="row">
    @if (fileUploadViewModels.Count > 0)
    {
        <table class="table table-responsive table-bordered">
            <thead class="text-primary">
                <tr>
                    <th>File</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var attachment in fileUploadViewModels)
                {

                    <tr>
                        <td>
                            <a class="text-primary"><i class="fa-solid fa-paperclip"></i> @attachment.FileName</a>
                        </td>                      
                       
                            <td>
                            <span class="oi oi-delete" aria-hidden="true" @onclick="() => OnFileDeleteClick(attachment)"></span>
                            </td>
                    </tr>
                }
            </tbody>
        </table>
    }
    else
    {
        <div class="alert alert-info">
            <strong>No Files!</strong>
        </div>
    }
</div>

@code {
    private string warninngMessage = "";
    private string displayMessage = "";
    private List<IBrowserFile> loadedFiles = new();
    private long maxFileSize = 1024 * 15;
    private int maxAllowedFiles = 3;
    private bool fileLoading;
    string Message = "No file(s) selected";
    IReadOnlyList<IBrowserFile> selectedFiles;
    private List<FileUploadViewModel> fileUploadViewModels = new();
    private void OnInputFileChange(InputFileChangeEventArgs e)
    {
        selectedFiles = e.GetMultipleFiles();
        Message = $"{selectedFiles.Count} file(s) selected";
        this.StateHasChanged();
    }
    private async void OnUploadSubmit()
    {
        fileLoading = true;
        foreach (var file in selectedFiles)
        {
            try
            {
                var trustedFileNameForFileStorage = file.Name;
                var blobUrl = await blobStorageService.UploadFileToBlobAsync(trustedFileNameForFileStorage, file.ContentType, file.OpenReadStream(20971520));
                if (blobUrl != null)
                {
                    FileUploadViewModel fileUploadViewModel = new FileUploadViewModel()
                        {
                            FileName = trustedFileNameForFileStorage,
                            FileStorageUrl = blobUrl,
                            ContentType = file.ContentType,
                        };

                    fileUploadViewModels.Add(fileUploadViewModel);
                    displayMessage = trustedFileNameForFileStorage + " Uploaded!!";
                }
                else
                    warninngMessage = "File Upload failed, Please try again!!";

            }
            catch (Exception ex)
            {
                warninngMessage = "File Upload failed, Please try again!!";
            }
        }

        fileLoading = false;
        this.StateHasChanged();
    }

    private async void OnFileDeleteClick(FileUploadViewModel attachment)
    {
        try
        {
            var deleteResponse = await blobStorageService.DeleteFileToBlobAsync(attachment.FileName);
            if (deleteResponse)
            {
                fileUploadViewModels.Remove(attachment);
                displayMessage = attachment.FileName + " Deleted!!";
            }
            
        }
        catch (Exception)
        {
            warninngMessage = "Something went wrong! Please try again.";
        }
        this.StateHasChanged();
    }

}

Let’s build and run the solution.

Uploading File into the Azure Blob Storage.

Let me show the uploaded file into Azure Blob from Azure Portal.

Go to the container and open it (rijsatdemo).

We can see the file in the Azure Blob container. We have successfully uploaded the file into Azure Blob Storage using the Blazor Server with .NET 7.

Likewise, we can delete the file using above the code as demonstrated.

This is how we can upload and delete files in Azure Blob Storage from a Blazor App with .NET 7.

You can find a complete Solution on GitHub, Click Here.

Conclusion

In this article, I have done a complete solution to upload and delete files in Azure Blob Storage from Blazor Application with .NET 7. Furthermore, I have demonstrated how to create an Azure Storage Account and a container for uploading files and documents. Then again, I have built a Blazor Server web application with .NET 7. At last, I did a complete solution to upload and delete files in Azure Blob Storage with code and showed an example. 

By Rijwan Ansari

Research and Technology Lead | Software Architect | Full Stack .NET Expert | Tech Blogger | Community Speaker | Trainer | YouTuber. Follow me @ https://rijsat.com Md Rijwan Ansari is a high performing and technology consultant with 10 plus years of Software Development and Business Applications implementation using .NET Technologies, SharePoint, Power Platform, Data, AI, Azure and cognitive services. He is also a Microsoft Certified Trainer, C# Corner MVP, Microsoft Certified Data Analyst Associate, Microsoft Certified Azure Data Scientist Associate, CSM, CSPO, MCTS, MCP, with 15+ Microsoft Certifications. He is a research and technology lead in Tech One Global as well as leading Facebook community Cloud Experts Group and SharePoint User Group Nepal. He is a active contributor and speaker in c-sharpcorner.com community, C# Corner MVP and his rank at 20 among 3+ millions members. Additionally, he is knee to learn new technologies, write articles, love to contribute to the open-source community. Visit his blog RIJSAT.COM for extensive articles, courses, news, videos and issues resolution specially for developer and data engineer.

Leave a Reply

Your email address will not be published. Required fields are marked *