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
- Example:
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.