- Published on
- 🍵 2 min read
Azure Emulators In Dotnet Aspire Development
- Authors
- Name
- Emin Vergil
- @eminvergil
Azure Emulators provide developers with a way to test their .NET Aspire applications locally, without incurring cloud costs or requiring an internet connection. These emulators replicate the behavior of Azure services, allowing developers to write and debug code as if it were running in the cloud.
Let's explore how to use Azure Emulators in a practical .NET Aspire application. We'll create a service that uploads contacts from an Excel file to a PostgreSQL database, utilizing Azure Blob Storage and Queue Storage.
First, let's look at the AppHost configuration:
App Host:
using Microsoft.Extensions.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres");
var contactDb = postgres.AddDatabase("contactdb");
var storage = builder.AddAzureStorage("Storage");
if (builder.Environment.IsDevelopment())
{
storage.RunAsEmulator(c => c.WithImageTag("3.31.0"));
}
var blobs = storage.AddBlobs("BlobConnection");
var queues = storage.AddQueues("QueueConnection");
builder.AddProject<Projects.Contact_Api>("contact-api")
.WithReference(blobs)
.WithReference(queues)
.WithReference(contactDb);
builder.AddProject<Projects.Contact_Worker>("contact-worker")
.WithReference(blobs)
.WithReference(queues)
.WithReference(contactDb);
builder.Build().Run();
In this configuration, we set up PostgreSQL, Azure Blob Storage, and Azure Queue Storage. Notice the RunAsEmulator
method, which is used to run the Azure Storage Emulator locally. It's important to specify a compatible version; in this case, we're using emulator version 3.31.0 for Aspire version 8.1.0.
The application consists of an API service for uploading files and a background worker for processing them. The API service uploads the file to Blob Storage and sends a message to the queue:
private static async Task<IResult> Upload(IFormFile file, QueueServiceClient queueServiceClient, BlobServiceClient blobServiceClient, CancellationToken cancellationToken)
{
var docsContainer = blobServiceClient.GetBlobContainerClient("fileuploads");
var queueClient = queueServiceClient.GetQueueClient("contacts");
var fileKey = Guid.NewGuid().ToString();
using var fileStream = file.OpenReadStream();
await docsContainer.UploadBlobAsync(fileKey, fileStream, cancellationToken);
await queueClient.SendMessageAsync(fileKey, cancellationToken);
return Results.Ok();
}
The background worker then processes the queue messages, downloads the files from Blob Storage, and saves the contact information to the database:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// ... (initialization code)
while (!stoppingToken.IsCancellationRequested)
{
QueueMessage[] messages = await queueClient.ReceiveMessagesAsync(maxMessages: 10, cancellationToken: stoppingToken);
foreach (var message in messages)
{
var fileKey = message.MessageText;
// ... (process the file and save to database)
}
await Task.Delay(5000, stoppingToken);
}
}
For the complete source code of this example, you can visit: https://github.com/eminvergil/aspire-samples