Modern apps work with files all the time—PDFs, images, invoices, contracts, and more. Azure Blob Storage is a great choice for storing these files because it’s secure and scales easily, and .NET 10 makes building the API simple and fast.
In this post, we’ll create a .NET 10 Web API that lets you upload multiple documents to Azure Blob Storage.
Architecture Overview
Flow
A client (Angular, React, Postman, etc.) uploads multiple files
The .NET 10 Web API receives the files using multipart/form-data
The API streams the files to Azure Blob Storage
The API returns blob URLs (or file metadata) back to the client
Tech Stack
.NET 10 Web API
Azure Blob Storage
Azure.Storage.Blobs SDK
Note: In this blog, I’ll focus only on the API side.
The source code can be downloaded from GitHub
Step 1: Create Azure Blob Storage
Create a Storage Account in Azure
Create a Blob Container
Grab:
Connection String
Container Name
Step 2: Install Required NuGet Package
Create a .NET Web API project in .NET 10 and install the below package.
dotnet add package Azure.Storage.Blobs
Step 3: Configure App Settings
Add the below settings into appsettings.json
{
"AzureBlobStorage": {
"ConnectionString": "DefaultEndpointsProtocol=...",
"ContainerName": "documents"
}
}
Step 4: Blob Storage Service using Dependency Injection
4.1 Create a Configure Options Class
- create a record as below
public record AzureBlobOptions
{
public string ConnectionString { get; init; } = string.Empty;
public string ContainerName { get; init; } = string.Empty;
}
4.2 Register Blob Client + Options in Program.cs
builder.Services.Configure<AzureBlobOptions>(
builder.Configuration.GetSection("AzureBlobStorage"));
builder.Services.AddSingleton(sp =>
{
var options = sp.GetRequiredService<IOptions<AzureBlobOptions>>().Value;
return new BlobContainerClient(
options.ConnectionString,
options.ContainerName);
});
Note: BlobContainerClient is thread-safe → Singleton is recommended.
4.3. Create an Interface and Implementation
This keep our controller clean and testable
public interface IBlobStorageService
{
Task<List<string>> UploadFilesAsync(List<IFormFile> files);
}
Implementation
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
public class BlobStorageService : IBlobStorageService
{
private readonly BlobContainerClient _containerClient;
public BlobStorageService(BlobContainerClient containerClient)
{
_containerClient = containerClient;
}
public async Task<List<string>> UploadFilesAsync(List<IFormFile> files)
{
var uploadedUrls = new List<string>();
await _containerClient.CreateIfNotExistsAsync(PublicAccessType.None);
foreach (var file in files)
{
if (file.Length <= 0)
continue;
var blobName = $"{Guid.NewGuid()}-{file.FileName}";
var blobClient = _containerClient.GetBlobClient(blobName);
await using var stream = file.OpenReadStream();
await blobClient.UploadAsync(
stream,
new BlobHttpHeaders { ContentType = file.ContentType });
uploadedUrls.Add(blobClient.Uri.ToString());
}
return uploadedUrls;
}
}
Step 5: Register the Service in Program.cs
builder.Services.AddScoped<IBlobStorageService, BlobStorageService>();
Step 6: Create the Upload API Endpoint
[ApiController]
[Route("api/documents")]
public class DocumentsController : ControllerBase
{
private readonly IBlobStorageService _blobStorageService;
public DocumentsController(IBlobStorageService blobStorageService)
{
_blobStorageService = blobStorageService;
}
[HttpPost("upload")]
[RequestSizeLimit(100_000_000)] // 100 MB
public async Task<IActionResult> UploadDocuments([FromForm] List<IFormFile> files)
{
if (files == null || files.Count == 0)
return BadRequest("No files uploaded.");
var urls = await _blobStorageService.UploadFilesAsync(files);
return Ok(new
{
Count = urls.Count,
Files = urls
});
}
}
Optional Enhancements (Highly Recommended)
It is always good to incorporate the below
Validate file type
Virus scan (Azure Defender for Storage Or integrate with a scanning service before upload)
Use Managed Identity - Avoid connection string in production and use Azure Managed Identity or Default Credentials
Conclusion
Connecting Azure Blob Storage with a .NET 10 Web API is simple if you keep the design clean and use dependency injection from the start. By streaming files straight from the API to Blob Storage, you avoid using too much memory and keep the solution scalable and ready for production.
In this post, we looked at how to accept multiple files using multipart/form-data, upload them efficiently to Azure Blob Storage, and organize the API using proper abstractions and dependency injection instead of tightly coupled code. This approach makes the code easier to test, maintain, and extend as your needs grow.
Note: This blog focuses only on the API side. Client-side uploads, UI details, and advanced security options like SAS tokens or Managed Identity can be added later if needed.
With this setup, you’re well prepared to handle document uploads in modern applications and can easily extend the solution to support metadata, validation, virus scanning, or secure downloads.
Happy Coding!