Implement Azure Blob Storage with .NET Core API (Production-Ready Guide)


Azure Blob Storage is one of the most reliable and scalable cloud storage services for modern applications. Whether you're building an e-commerce platform, document management system, or media service, Azure Blob Storage provides secure and cost-effective storage for files, images, videos, and backups.

In this blog, we’ll build a production-ready ASP.NET Core Web API that supports:

  • File upload
  • File download
  • File delete
  • Secure configuration
  • Dependency Injection
  • Container auto-creation
  • Unique file naming
  • Clean architecture approach
  • Error handling and logging best practices

By the end, you’ll have a real-world implementation ready for enterprise applications.

Why Azure Blob Storage?

Azure Blob Storage is ideal because it offers:

  • Massive scalability
  • High availability
  • Secure access control
  • CDN integration
  • Backup and disaster recovery
  • Low storage cost
  • SDK support for .NET

Typical use cases:

  • Profile image storage
  • Invoice/document storage
  • Video streaming
  • Application backups
  • Data archival

Prerequisites

Before starting, make sure you have:

  • .NET 8 SDK or .NET 7 SDK
  • Azure Subscription
  • Azure Storage Account
  • Visual Studio / VS Code

Step 1: Create Azure Storage Account

Go to Azure Portal:

  • Create a Storage Account
  • Navigate to:
    • Storage Account → Containers
  • Create a container:
    • Example: documents

Set access level:

  • Private (recommended for production)

Now copy:

  • Storage Account Connection String

Step 2: Create ASP.NET Core Web API

Create a new project:

dotnet new webapi -n BlobStorageApi

Navigate to project:

cd BlobStorageApi

Step 3: Install Azure Blob Storage SDK

Install NuGet package:

dotnet add package Azure.Storage.Blobs

Step 4: Configure appsettings.json

{
  "AzureBlobStorage": {
    "ConnectionString": "YOUR_CONNECTION_STRING",
    "ContainerName": "documents"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Production Tip:
Never store secrets directly in source control.

Use:

  • Azure Key Vault
  • Environment Variables
  • Managed Identity

Step 5: Create Storage Settings Model

Create:

Models/AzureBlobStorageSettings.cs

namespace BlobStorageApi.Models;

public class AzureBlobStorageSettings
{
    public string ConnectionString { get; set; } = string.Empty;
    public string ContainerName { get; set; } = string.Empty;
}

Step 6: Create Blob Service Interface

Services/Interfaces/IBlobService.cs

namespace BlobStorageApi.Services.Interfaces;

public interface IBlobService
{
    Task<string> UploadFileAsync(IFormFile file);
    Task<Stream?> DownloadFileAsync(string fileName);
    Task<bool> DeleteFileAsync(string fileName);
}

Step 7: Implement Blob Service

Services/BlobService.cs

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using BlobStorageApi.Models;
using BlobStorageApi.Services.Interfaces;
using Microsoft.Extensions.Options;

namespace BlobStorageApi.Services;

public class BlobService : IBlobService
{
    private readonly BlobContainerClient _containerClient;
    private readonly ILogger<BlobService> _logger;

    public BlobService(
        IOptions<AzureBlobStorageSettings> settings,
        ILogger<BlobService> logger)
    {
        _logger = logger;

        var blobServiceClient = new BlobServiceClient(
            settings.Value.ConnectionString);

        _containerClient = blobServiceClient.GetBlobContainerClient(
            settings.Value.ContainerName);

        _containerClient.CreateIfNotExists(
            PublicAccessType.None);
    }

    public async Task<string> UploadFileAsync(IFormFile file)
    {
        if (file == null || file.Length == 0)
            throw new ArgumentException("Invalid file.");

        var extension = Path.GetExtension(file.FileName);

        var fileName =
            $"{Guid.NewGuid()}{extension}";

        var blobClient =
            _containerClient.GetBlobClient(fileName);

        using var stream = file.OpenReadStream();

        await blobClient.UploadAsync(
            stream,
            new BlobHttpHeaders
            {
                ContentType = file.ContentType
            });

        _logger.LogInformation(
            "File uploaded successfully: {FileName}",
            fileName);

        return fileName;
    }

    public async Task<Stream?> DownloadFileAsync(
        string fileName)
    {
        var blobClient =
            _containerClient.GetBlobClient(fileName);

        if (!await blobClient.ExistsAsync())
            return null;

        var response =
            await blobClient.DownloadStreamingAsync();

        return response.Value.Content;
    }

    public async Task<bool> DeleteFileAsync(
        string fileName)
    {
        var blobClient =
            _containerClient.GetBlobClient(fileName);

        var response =
            await blobClient.DeleteIfExistsAsync();

        if (response.Value)
        {
            _logger.LogInformation(
                "File deleted: {FileName}",
                fileName);
        }

        return response.Value;
    }
}

Step 8: Register Services in Program.cs

Program.cs

using BlobStorageApi.Models;
using BlobStorageApi.Services;
using BlobStorageApi.Services.Interfaces;

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<AzureBlobStorageSettings>(
    builder.Configuration.GetSection("AzureBlobStorage"));

builder.Services.AddScoped<IBlobService, BlobService>();

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI();

app.UseHttpsRedirection();

app.MapControllers();

app.Run();

Step 9: Create Blob Controller

Controllers/BlobController.cs

using BlobStorageApi.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace BlobStorageApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BlobController : ControllerBase
{
    private readonly IBlobService _blobService;

    public BlobController(
        IBlobService blobService)
    {
        _blobService = blobService;
    }

    [HttpPost("upload")]
    [RequestSizeLimit(100_000_000)]
    public async Task<IActionResult> Upload(
        IFormFile file)
    {
        if (file == null)
            return BadRequest("File is required.");

        var fileName =
            await _blobService.UploadFileAsync(file);

        return Ok(new
        {
            Message = "File uploaded successfully.",
            FileName = fileName
        });
    }

    [HttpGet("download/{fileName}")]
    public async Task<IActionResult> Download(
        string fileName)
    {
        var stream =
            await _blobService.DownloadFileAsync(fileName);

        if (stream == null)
            return NotFound();

        return File(
            stream,
            "application/octet-stream",
            fileName);
    }

    [HttpDelete("{fileName}")]
    public async Task<IActionResult> Delete(
        string fileName)
    {
        var deleted =
            await _blobService.DeleteFileAsync(fileName);

        if (!deleted)
            return NotFound();

        return Ok(new
        {
            Message = "File deleted successfully."
        });
    }
}

Step 10: Run the API

Run project:

dotnet run

Swagger opens:

https://localhost:xxxx/swagger

Test:

  • Upload file
  • Download file
  • Delete file

Production Best Practices

1. Use Managed Identity

Avoid connection strings in production.

Preferred approach:

  • Azure Managed Identity
  • Azure RBAC

Example:

var blobServiceClient = new BlobServiceClient(
    new Uri("https://yourstorage.blob.core.windows.net"),
    new DefaultAzureCredential());

Install:

dotnet add package Azure.Identity

2. Validate File Types

Never trust uploaded files.

Example validation:

var allowedExtensions =
    new[] { ".jpg", ".png", ".pdf" };

if (!allowedExtensions.Contains(extension))
{
    throw new Exception("Invalid file type.");
}

3. Limit File Size

Prevent abuse:

if (file.Length > 10 * 1024 * 1024)
{
    throw new Exception("File too large.");
}

4. Generate Secure File Names

Never use original filenames directly.

Good:

Guid.NewGuid()

Bad:

file.FileName

5. Add Retry Policies

Azure SDK supports retries automatically, but enterprise systems often configure explicit resilience policies.

6. Enable Application Insights

Track:

  • Upload failures
  • Latency
  • Storage exceptions
  • Traffic patterns

7. Use SAS Tokens for Secure Access

Instead of exposing blobs publicly, generate temporary signed URLs.

Example use cases:

  • Download invoices
  • Temporary image access
  • Secure file sharing

Example Folder Structure

BlobStorageApi
│
├── Controllers
├── Models
├── Services
│   ├── Interfaces
│   └── BlobService.cs
├── appsettings.json
└── Program.cs

Common Production Scenarios

Image Upload Service

Store:

  • User profile images
  • Product images
  • Thumbnails

Document Management System

Store:

  • PDFs
  • Contracts
  • Invoices
  • Reports

Video Storage Platform

Store:

  • MP4 videos
  • Media streaming content

Performance Tips

For large files:

  • Use chunk uploads
  • Use streaming
  • Avoid loading entire file into memory
  • Azure Blob Storage handles multi-GB files efficiently.

Security Recommendations

Always:

  • Keep containers private
  • Use HTTPS only
  • Rotate keys regularly
  • Enable Defender for Storage
  • Scan uploaded files for malware

Keep coding, Happy Coding.

0 Comments Report