Blog Post

Educator Developer Blog
3 MIN READ

Seamless File Management in ASP.NET Core: Azure Blob Storage with Configurable Local Mode

SyedShahriyar's avatar
SyedShahriyar
Brass Contributor
Jan 14, 2025

Managing file uploads in a web application can be a challenging task, especially when balancing between development environments and production needs. In this blog, I’ll walk you through a solution that uses Azure Blob Storage for production and a configurable local storage for development in an ASP.NET Core Web API.

Setting up the Project

Before we dive into the implementation, let’s set up the basic structure:

  1. Create an ASP.NET Core Web API project.
  2. Add the Azure.Storage.BlobsNuGet Package for Azure Blob Storage integration.
  3. Update appsettings.json to include storage configurations:
"Storage": {
    "Mode": "Local",
    "BlobStorage": {
        "ConnectionString": "YourAzureBlobStorageConnectionString",
        "ContainerName": "YourContainerName"
    }
}
  • Mode: Determines whether to use Local or Azure Blob Storage.
  • ConnectionString and ContainerName: Azure Blob Storage details.

Implementing the Storage Service

Here is a custom StorageService that handles file uploads, deletions, and downloads. It dynamically decides the storage location based on the configuration mode.

public class StorageService : IStorageService
{
    private readonly IConfiguration _configuration;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly string _storageMode;

    public StorageService(IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
    {
        _configuration = configuration;
        _httpContextAccessor = httpContextAccessor;
        _storageMode = _configuration["Storage:Mode"];
    }

    public async Task<string> UploadFile(IFormFile file)
    {
        try
        {
            if (_storageMode == "Local")
            {
                var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");
                var fileName = $"{DateTime.Now:MMddss}-{file.FileName}";
                var filePath = Path.Combine(uploads, fileName);

                if (!Directory.Exists(uploads))
                    Directory.CreateDirectory(uploads);

                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(fileStream);
                }

                var host = string.Format("{0}{1}",
                    _httpContextAccessor.HttpContext!.Request.IsHttps ? "https://" : "http://",
                    _httpContextAccessor.HttpContext.Request.Host);

                return $"{host}/uploads/{fileName}";
            }
            else
            {
                var container = new BlobContainerClient(_configuration["Storage:BlobStorage:ConnectionString"], _configuration["Storage:BlobStorage:ContainerName"]);
                await container.CreateIfNotExistsAsync(PublicAccessType.Blob);

                var blob = container.GetBlobClient(file.FileName);
                using (var fileStream = file.OpenReadStream())
                {
                    await blob.UploadAsync(fileStream, new BlobHttpHeaders { ContentType = file.ContentType });
                }

                return blob.Uri.ToString();
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    public async Task<bool> DeleteFile(string fileName)
    {
        try
        {
            if (_storageMode == "Local")
            {
                var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");
                var filePath = Path.Combine(uploads, fileName);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                    return true;
                }
            }
            else
            {
                var container = new BlobContainerClient(_configuration["Storage:BlobStorage:ConnectionString"],_configuration["Storage:BlobStorage:ContainerName"]);
                var blob = container.GetBlobClient(fileName);
                await blob.DeleteIfExistsAsync();
                return true;
            }
        }
        catch (Exception ex)
        {
            return false;
        }
    }

    public byte[] DownloadFile(string fileName)
    {
        var blobServiceClient = new BlobServiceClient(_configuration["Storage:BlobStorage:ConnectionString"]);
        var container = blobServiceClient.GetBlobContainerClient(_configuration["Storage:BlobStorage:ContainerName"]);
        var blobClient = container.GetBlobClient(fileName);

        using (var memoryStream = new MemoryStream())
        {
            blobClient.DownloadTo(memoryStream);
            return memoryStream.ToArray();
        }
    }
}

Static File Middleware

Add app.UseStaticFiles(); in Program.cs to serve local files.

Usage Example

Here’s how to use the UploadFile method in a Web API:

public async Task<ServiceResponse<List<ProductPicture>>> UploadImages(List<IFormFile> images)
{
    ServiceResponse<List<ProductPicture>> response = new();

    try
    {
        List<ProductPicture> pictures = new();

        foreach (var file in images)
        {
            var imageUrl = await _storageService.UploadFile(file);
            pictures.Add(new ProductPicture { Url = imageUrl, FileName = Path.GetFileName(imageUrl) });
        }

        response.Data = pictures;
    }
    catch (Exception ex)
    {
        response.Success = false;
        response.Message = ex.Message;
    }

    return response;
}

Conclusion

By integrating Azure Blob Storage and providing a configurable local storage mode, this approach ensures flexibility for both development and production environments. It reduces development friction while leveraging Azure’s scalability when deployed.

For further details, explore the Azure Blob Storage Documentation and Quickstart: Azure Blob Storage.

Updated Jan 21, 2025
Version 2.0
No CommentsBe the first to comment