Integrating Azure Blob Storage with .NET

Introduction

Azure Blob Storage is a powerful cloud-based storage solution provided by Microsoft Azure. In ASP.NET Core 8 applications, integrating Azure Blob Storage enables seamless storage and retrieval of files like images, documents, and videos. In this article, we'll walk through the process of setting up Azure Blob Storage with ASP.NET Core 8 MVC, including configuration, implementation, and basic operations like uploading, downloading, and deleting files.

ASP.NET Core

In this article, we'll explore how to integrate Azure Blob Storage with an ASP.NET Core 8 MVC application. We'll focus on creating a dedicated BlobStorageController to perform all blob-related operations, including listing files, uploading, deleting, and downloading.

Step 1. Setting Up Azure Blob Storage

Before we proceed, you need to create an Azure Storage Account. If you're unsure how to create an Azure Storage Account, refer to the article "Understanding and Creation of Azure Storage Account". Once your storage account is created, navigate to your storage account and go to the "Access Key" section to get your connection string. Copy your connection string from here and keep it for the next step.

Access Key

Step 2. Configuring the ASP.NET Core Application

In your ASP.NET Core project, open the appsettings.json file. This file contains configuration settings for your application. Add the following configuration snippet, replacing "YourConnectionStringHere" with the connection string obtained from the Azure portal:

{
  "ConnectionStrings": {
    "StorageAccount": "YourConnectionStringHere"
  }
}

Step 3. Registering Blob Service Client

In this step, we'll register the Blob Service Client in the ASP.NET Core application's services. This registration will allow us to inject the Blob Service Client into the BlobStorageController for seamless interaction with Azure Blob Storage.

using Azure.Storage.Blobs;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

//register blob service client by reading StorageAccount connection string from appsettings.json
builder.Services.AddSingleton(x => new BlobServiceClient(builder.Configuration.GetConnectionString("StorageAccount")));


var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

By registering the Blob Service Client as a singleton service, we ensure that a single instance of the client is shared throughout the application's lifetime. This allows for efficient management of connections to Azure Blob Storage and promotes scalability and performance in handling file operations. With the Blob Service Client registered, we can now inject it into the BlobStorageController to perform various blob-related operations seamlessly.

Step 4. Performing Blob Operations

In our ASP.NET Core MVC application, we'll create a dedicated BlobStorageController to manage interactions with Azure Blob Storage.

Before we start integrating Azure Blob Storage into our ASP.NET Core 8 MVC application, we need to install Azure.Storage.Blobs NuGet package. This package provides the necessary libraries to interact with Azure Blob Storage.

Blob Operations

We define constants for the container name, success message key, and error message key, providing meaningful identifiers for better code readability and maintenance.


    private const string ContainerName = "myfiles";
    public const string SuccessMessageKey = "SuccessMessage";
    public const string ErrorMessageKey = "ErrorMessage";

    private readonly BlobServiceClient _blobServiceClient;
    private readonly BlobContainerClient _containerClient;

    public BlobStorageController(BlobServiceClient blobServiceClient)
    {
        _blobServiceClient = blobServiceClient;
        _containerClient = _blobServiceClient.GetBlobContainerClient(ContainerName);
        _containerClient.CreateIfNotExists(); 
    }

In the constructor of the BlobStorageController, we initialize the Blob Service Client and the Blob Container Client. The Blob Container is created if it does not already exist. This setup ensures that the controller is ready to interact with the specified container in Azure Blob Storage for file operations.

 BlobStorageController

Upload Files


    public IActionResult Upload()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        try
        {
            var blobClient = _containerClient.GetBlobClient(file.FileName);
            await blobClient.UploadAsync(file.OpenReadStream(), true);
            TempData[SuccessMessageKey] = "File uploaded successfully.";
        }
        catch (Exception ex)
        {
            TempData[ErrorMessageKey] = "An error occurred while uploading the file: " + ex.Message;
            return View();
        }

        return RedirectToAction("Index");
    }

The Upload action in the BlobStorageController enables users to upload files to Azure Blob Storage. Here's how it works:

  • When a user submits a file through the upload form, the ASP.NET Core application receives the file as an instance of IFormFile.
  • Inside the Upload action method, we create a BlobClient object by specifying the filename and obtaining a reference to the blob within the container in Azure Blob Storage.
  • Using the UploadAsync method, we upload the file asynchronously to the specified blob in the container. The file's content is streamed from the client to Azure Blob Storage.
  • If the upload is successful, a success message is stored in TempData, which will be displayed to the user. If an error occurs during the upload process, an error message is stored in TempData.
     TempData.

Retrieve Files


    public async Task<IActionResult> Index()
    {
        var blobs = new List<string>();
        await foreach (var blobItem in _containerClient.GetBlobsAsync())
        {
            blobs.Add(blobItem.Name);
        }
        return View(blobs);
    }

The Index action retrieves a list of all files stored in the container in Azure Blob Storage. Here's a breakdown of how it functions:

  • The Index action asynchronously fetches the list of blobs (files) stored within the container using the GetBlobsAsync method.
  • As each blob is enumerated asynchronously, its name is added to a list of strings representing the filenames.
  • This list of filenames is then passed to the Index view, where it is displayed to the user.
    Index action

Download Files


    public async Task<IActionResult> Download(string fileName)
    {
        try
        {
            var blobClient = _containerClient.GetBlobClient(fileName);
            var memoryStream = new MemoryStream();
            await blobClient.DownloadToAsync(memoryStream);
            memoryStream.Position = 0;
            var contentType = blobClient.GetProperties().Value.ContentType;
            return File(memoryStream, contentType, fileName);
        }
        catch (Exception ex)
        {
            TempData[ErrorMessageKey] = "An error occurred while downloading the file: " + ex.Message;
            return RedirectToAction("Index");
        }
    }

The Download action allows users to download files from Azure Blob Storage. Here's how it operates.

  • When a user requests to download a file, the Download action is invoked with the filename of the desired blob.
  • The action retrieves the corresponding BlobClient object for the specified filename.
  • Using the DownloadToAsync method, the blob's content is downloaded asynchronously into a memory stream.
  • The memory stream is then returned as a FileResult, allowing the user's browser to prompt for download with the appropriate filename and content type.

Delete Files


    public async Task<IActionResult> Delete(string fileName)
    {
        try
        {
            var blobClient = _containerClient.GetBlobClient(fileName);
            await blobClient.DeleteIfExistsAsync();
            TempData[SuccessMessageKey] = "File deleted successfully.";
        }
        catch (Exception ex)
        {
            TempData[ErrorMessageKey] = "An error occurred while deleting the file: " + ex.Message;
        }
        return RedirectToAction("Index");
    }

The Delete action enables users to delete files from Azure Blob Storage. Here's how it functions.

  • When a user requests to delete a file, the Delete action is invoked with the filename of the blob to be deleted.
  • The action retrieves the corresponding BlobClient object for the specified filename.
  • Using the DeleteIfExistsAsync method, the blob is deleted asynchronously from the container.
  • If the deletion is successful, a success message is stored in TempData. If an error occurs during the deletion process, an error message is stored in TempData.

Step 4. Creating Views

In this step, we'll create views for the BlobStorageController to provide user interfaces for uploading, downloading, and managing files. Specifically, we'll create two views: Index.cshtml and Upload.cshtml.

Index. cshtml

This view will display a list of files stored in Azure Blob Storage, allowing users to view and interact with them. It will include functionalities such as listing files, downloading files, and deleting files.

The Index view will typically consist of an HTML table displaying the list of files retrieved from Azure Blob Storage. Each file listed may have associated actions such as downloading or deleting. The view will be bound to the model containing the list of filenames retrieved from the BlobStorageController.

@model List<string>

@{
    ViewData["Title"]="Blob Storage";
    var errorMessage = TempData[AspNetMVCWithAzure.Controllers.BlobStorageController.ErrorMessageKey] as string;
    var successMessage = TempData[AspNetMVCWithAzure.Controllers.BlobStorageController.SuccessMessageKey] as string;
}

@if (!string.IsNullOrEmpty(errorMessage))
{
    <div class="alert alert-danger  mb-2" role="alert">
        @errorMessage
    </div>
}

@if (!string.IsNullOrEmpty(successMessage))
{
    <div class="alert alert-success mb-2" role="alert">
        @successMessage
    </div>
}

<a asp-controller="BlobStorage" asp-action="Upload" class="btn btn-primary">Upload New File</a>

<table class="table table-bordered mt-3">
    <thead class="thead-dark">
        <tr>
            <th>File Name</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        @if (Model.Count > 0)
        {
            @foreach (var fileName in Model)
            {
                <tr>
                    <td>@fileName</td>
                    <td>
                        <a asp-controller="BlobStorage" asp-action="Download" asp-route-fileName="@fileName" class="btn btn-success">Download</a>
                        <a asp-controller="BlobStorage" asp-action="Delete" asp-route-fileName="@fileName" class="btn btn-danger">Delete</a>
                    </td>
                </tr>
            }
        }
        else
        {
            <tr>
                <td colspan="2" class="text-center"><b>No files found.</b></td>
            </tr>
        }
    </tbody>
</table>

Upload.cshtml

This view will contain a form that allows users to upload files to Azure Blob Storage. Users can select a file from their local system and submit it to be stored in the container.

The Upload view will contain an HTML form with a file input field, allowing users to select a file from their local system. Upon submission of the form, the selected file will be uploaded to Azure Blob Storage via the Upload action in the BlobStorageController.

<h2>Upload File</h2>

@{
    ViewData["Title"] = "Upload New File";
    var errorMessage = TempData[AspNetMVCWithAzure.Controllers.BlobStorageController.ErrorMessageKey] as string;
    var successMessage = TempData[AspNetMVCWithAzure.Controllers.BlobStorageController.SuccessMessageKey] as string;
}

@if (!string.IsNullOrEmpty(errorMessage))
{
    <div class="alert alert-danger  mb-2" role="alert">
        @errorMessage
    </div>
}

@if (!string.IsNullOrEmpty(successMessage))
{
    <div class="alert alert-success mb-2" role="alert">
        @successMessage
    </div>
}


<div class="row">
    <div class="col-md-6">
        <form method="post" enctype="multipart/form-data" asp-action="Upload">
            <div class="row">
                <div class="col-md-12">
                    <label for="file">Select File:</label>
                </div>
                <div class="col-md-12">
                    <input type="file" class="form-control-file" id="file" name="file" required>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col-md-12">
                    <button type="submit" class="btn btn-primary">Upload</button>
                    <a asp-action="Index" class="btn btn-secondary">Back</a>
                </div>
            </div>
        </form>
    </div>
</div>

Output

Upload file

Conclusion

In this article, we've learned how to integrate Azure Blob Storage with ASP.NET Core 8 MVC applications using a dedicated BlobStorageController. By following the steps outlined above, you can efficiently manage files in your web applications using Azure Blob Storage.

To access the code referenced in this article, please visit the GitHub repository. Additionally, for guidance on deploying your .NET MVC application to Azure App Services, refer to the article 'Deploying a .NET MVC App on Azure App Services' for detailed instructions.