Table of Contents
.NET Aspire makes it easy to use Azure Storage for local agent development with the Microsoft Agent Framework.
In this post, we’ll look at how to set up Azure Storage with Azurite using .NET Aspire so you have a reliable way to persist agent state between requests.
You can find the code here
You Have To Start Somewhere
The first thing to address when building Microsoft Agent Framework applications is state.
- Templates: Prompt templates and system messages
- Conversation history: Threads, turns, and messages
Models deployed on Azure are stateless by design, so your application needs to load templates, conversation histories, and any other state before invoking the model. After the LLM responds, you persist the result and return the response to the user.
Azure Blob Storage provides a simple way to store templates and chat history during local development. In production, you might choose Cosmos DB to model complex conversations or to support efficient querying.
Start simple, get the architecture right, and you can swap Azure Storage for Cosmos DB or MongoDB without major changes.
(You could also create an agent on Azure Foundry and offload this work—but you’d miss out on a valuable learning experience!)
The Application
The application is built with ASP.NET Core, C#, and .NET Aspire. It follows principles inspired by Jason Taylor’s Clean Architecture:
.NET Aspire simplifies building and running locally distributed applications. It also makes it easy to run an ASP.NET Core app alongside a containerized Azurite instance (Azure Storage emulator).
Azure Local Storage with Azurite
Setting up Azure local storage (Azurite) in .NET Aspire can be done in one line of code, plus an optional data bind mount for persistence between runs.
const string storageName = "storage";
const string storageData = "../Storage/Data";
const string blobStorageConnectionName = "blobs";
var storage = builder.AddAzureStorage(storageName)
.RunAsEmulator(resourceBuilder =>
{ resourceBuilder.WithDataBindMount(storageData); });
var blobs = storage.AddBlobs(blobStorageConnectionName);Naming Your Resource
When you add a storage resource to the Aspire host builder, Aspire spins up an Azurite container when using RunAsEmulator and writes the connection details to the settings file. You can then use Aspire’s extensions to read those settings, locate the Azurite instance, and inject the required client through DI.
In this case we create a BlobServiceClient:
builder.Services.AddAzureClients(azure =>
{
var cs = builder.Configuration.GetConnectionString("blobs");
azure.AddBlobServiceClient(cs);
});Persisting Your Data Locally
Binding a local folder to the container ensures your data persists after the application stops. The storage folder can live at the same level as your project folders and should be excluded from source control.
Below is an example of using Azure Blob Storage to load an agent template and save a chat turn.
Using it in Your Application
Add Azure clients using dependency injection, then inject BlobServiceClient into your repositories.
public class AzureStorageRepository(
BlobServiceClient blobServiceClient,
ILogger<AzureStorageRepository> logger) : IAzureStorageRepository
{
public async Task UploadTextBlobAsync(string containerName)
{
var client = blobServiceClient.GetBlobContainerClient(containerName);
}.NET Aspire takes care of service discovery and connection strings, so the BlobServiceClient is fully configured and ready to use.
What's Next?
With Azurite integrated into your .NET Aspire setup, you now have a reliable local storage solution for managing agent templates and conversation state when building with the Microsoft Agent Framework. This foundation sets you up for more advanced state handling and smoother transitions to production-ready storage options.