Getting Started with .NET Aspire
Saturday, 17 May 2025
In this blog post, we'll take our first steps with .NET Aspire, Microsoft's new application model for building, running, and observing cloud-native applications. We'll explore how Aspire simplifies development workflows, enhances local development experiences, and streamlines deployments to Azure.
To bring this to life, I’ve built a demo project: Aspire Chat Demo. This will serve as our working example throughout this post and future posts. This example is starting from scratch with Aspire. I'll be doing another blog post soon on how you can start to integrate Aspire into an existing project.
What is .NET Aspire? 🏗️
.NET Aspire is an opinionated, cloud-native development stack designed to simplify building and running distributed applications. It brings together multiple tools, patterns, and integrations to help developers model, compose, and observe their applications more effectively.
Aspire introduces the concept of an App Host to manage the lifecycle of your services, along with resource projections for managing cloud dependencies like Redis or SQL databases. With deep integration into Visual Studio, Visual Studio Code, JetBrains Rider and a streamlined CLI, Aspire enhances both local development and cloud deployments.
Key benefits of Aspire:
- Simplifies orchestration with App Hosts
- Provides unified and managed development environments
- Boosts productivity with streamlined local resource emulation
- First-class observability out-of-the-box with metrics, logs, and distributed tracing
For a more detailed overview, check out my related post: Why you should try Aspire
Setting Up .NET Aspire and the Aspire CLI 🛠️
Let's get Aspire and the chat demo up and running!
Prerequisites
Before you start, make sure you have these installed:
- .NET 9 SDK
- Docker Desktop
- Aspire CLI
- Azure CLI & Azure Developer CLI (azd)
- An IDE like Visual Studio 2022+, Rider, or VS Code
- Azure subscription
Run the Demo
Install Aspire Cli:
dotnet tool install --global aspire.cli --prerelease
Clone the repo:
git clone https://github.com/intrepid-developer/aspire-chat-demo.git
cd aspire-chat-demo/AspireChat/AspireChat.AppHost
Start the App:
aspire run
You should then see it boot up in your terminal:
Demo App Overview: Aspire Chat Demo 💬
The Aspire Chat Demo is a modern, real-time chat application built with .NET Aspire and Azure, designed to demonstrate cloud-native application development patterns. It serves as a practical example of how Aspire can simplify the development of distributed applications.
This project showcases:
- Integration of Azure services with a modern .NET stack
- Scalable and resilient architecture for real-time communication
- Observability and orchestration using Aspire's App Host and dashboard
While the primary focus is on Aspire, this demo will evolve over time and be the foundation for a series of blog posts exploring best practices, patterns, and real-world scenarios.
Technology Stack 🧰
The Aspire Chat Demo leverages a modern technology stack to demonstrate cloud-native development patterns:
- .NET Aspire: Provides orchestration, resource projections, and observability
- FastEndpoints: Lightweight, high-performance API framework following the REPR pattern
- Blazor Server: Delivers a rich, interactive web UI with C# on the server side
- Entity Framework Core: Simplifies data access and interactions with SQL databases
- Redis: Supports caching of requests
- Azure SQL Database: Reliable, managed relational database service
- Azure Blob Storage: Handles file attachments and image storage
- Azure Container Apps: Hosts containerised backend and frontend services
This robust stack showcases how Aspire integrates with Azure services and modern .NET technologies to build scalable, observable applications.
Project Structure 🏛️
The Aspire Chat Demo uses Aspire to orchestrate our monolithic application. We have a traditional Api (powered by FastEndpoints) and a Blazor Server front end.
Projects
- AspireChat.AppHost: Coordinates and orchestrates all services and infrastructure, providing observability and configuration defaults.
- AspireChat.Api: Backend API service built with FastEndpoints, responsible for handling chat messages, user interactions, and API logic.
- AspireChat.Web: Blazor Server frontend application delivering the interactive chat user interface.
- AspireChat.ServiceDefaults: Contains shared configurations and defaults used across multiple services for consistency and maintainability.
Infrastructure Components
- ACA: Azure Container Apps will be used to host the Api and Web projects
- Redis: Utilised for request caching.
- SQL Server: Handles data persistence for user information and chat history.
- Azure Blob Storage: Manages file attachments and image uploads.
Our App Host
The App Host ties these services together, enabling streamlined development workflows, managing dependencies, and providing out-of-the-box observability through the Aspire dashboard and dependency graphs. These tools give clear insights into what's happening inside your application, making it much easier to diagnose issues and stay proactive as your applications grow in size and complexity. With metrics, traces, and visualisations, Aspire helps you pinpoint areas for improvement and keep your system healthy and efficient.
Here’s what our App Host looks like.
//======================================================================
// ASPIRE CHAT APPLICATION HOST
//======================================================================
// This file defines the architecture of our entire application.
// The AppHost project orchestrates all services, databases, and
// infrastructure components that make up our application.
var builder = DistributedApplication.CreateBuilder(args);
//======================================================================
// DEPLOYMENT CONFIGURATION
//======================================================================
builder.AddAzureContainerAppEnvironment("aspire-chat");
//======================================================================
// INFRASTRUCTURE SERVICES
//======================================================================
var cache = builder.AddRedis("cache").WithRedisInsight();
var sqlServer = builder.AddAzureSqlServer("sql").RunAsContainer();
var database = sqlServer.AddDatabase("db");
var storage = builder.AddAzureStorage("storage").RunAsEmulator();
var blobStorage = storage.AddBlobs("blobs");
//======================================================================
// APP PARAMETERS AND SECRETS
//======================================================================
var jwtKey = builder.AddParameter("jwt-key", secret: true);
//======================================================================
// APPLICATION COMPONENTS
//======================================================================
var api = builder.AddProject("api")
.WithHttpsHealthCheck("/health")
.WithEnvironment("JWT_KEY", jwtKey)
.WithReference(blobStorage).WaitFor(blobStorage)
.WithReference(cache).WaitFor(cache)
.WithReference(database).WaitFor(database);
var web = builder.AddProject("web")
.WithExternalHttpEndpoints()
.WithHttpsHealthCheck("/health")
.WithReference(cache).WaitFor(cache)
.WithReference(api).WaitFor(api);
//======================================================================
// BUILD AND RUN
//======================================================================
builder.Build().Run();
Compute Environments
Aspire 9.3 has improved the setup of Publishers or as they're now known Compute Environments. These allow you to tell Aspire where you want resources to run when published. You can have several Compute Environments if you want (such as Docker and Kubernetes). If you're using more than 1 compute environment you will have to tell each resource which environment it's running on using .WithComputeEnvironment(env), though this isn't required if you're only using 1 environment. See my blog Using Aspire with Docker Hosts to find out how to publish to non-Azure hosts like DigitalOcean.
Azure Container App Host
Next, we add an Azure Container App host. This tells Aspire that when it comes to publishing this app we want to use Azure Container Apps. It allows direct configuration of the container host, giving you more control compared to letting azd create it automatically.
Infrastructure Services
We then define our core infrastructure components. These services are the foundation of our application and are managed by Aspire to ensure seamless local development and straightforward cloud deployment.
- Redis Cache: Redis is used for caching our requests. In this setup we'll be using Redis as a docker container both locally and when published to Azure. Redis Insight is integrated for monitoring and inspecting cache activity during development. We could also have the option to use Azure Managed Redis Cache when we deployed, but that's an expensive service we don't need for this demo.
- SQL Server & Database: SQL Server serves as the primary data store for chat history, user profiles, and application data. Locally, it runs inside a Docker container using .RunAsContainer(), allowing developers to work without needing a dedicated database server. Aspire automates the setup, ensuring consistency across environments. When deploying to Azure, Aspire generates the necessary Bicep templates to provision an Azure SQL Database, making the transition from local to cloud seamless.
- Azure Storage Account: File uploads and image attachments in the chat application are handled by Azure Storage. For development, the Azurite emulator replicates Azure Storage functionality locally using .RunAsEmulator(). This allows developers to test storage interactions without incurring cloud costs. Upon deployment, Aspire provisions an actual Azure Storage Account, ensuring the app behaves consistently in both environments.
By defining these infrastructure services declaratively within the AppHost, Aspire ensures that developers can focus on building features while maintaining a clear and automated path from local development to production deployment.
Config and Secrets
One of Aspire's best features is allowing us to define what our application needs in C#. By defining all our configuration values and secrets we have a source of truth for our application. In this demo we're not using something like KeyVault to secure them, but we could if we wanted to. We add a new parameter jwt-key and set it as a secret (meaning it's loaded from UserSecrets locally) so that the AppHost knows to publish it as a secret. We then use this parameter later on for the Api's environment variables.
Application Components
Finally, we configure our API and Web applications:
- WithReference() links apps to their required resources.
- WaitFor() ensures services are healthy before starting dependent apps.
- Environment Variables like JWT_KEY are injected where needed.
Orchestration
With these definitions in place, the AppHost can orchestrate services for local development and generate the necessary artifacts for cloud deployments. Aspire handles the heavy lifting, letting you focus on building features.
Publishing to Azure ☁️
Once your app is running locally, deploying to Azure is the next logical step. We'll be using the Azure Developer CLI (azd) to publish it. The Aspire Cli can publish artifacts but it doesn't handle deployment (as of writing), it's still in preview as well. I'll do another blog post on the Aspire CLI when it's out of preview. The current recommended approach for publishing and deploying to Azure is to use azd.
Prerequisites
Before deploying, ensure you have:
- Azure CLI installed: You can download and install it from Azure CLI Documentation.
- Azure Developer CLI installed: You can download and install it from Azure Developer Cli
- Signed into your Azure account: az login
Run the command:
azd init
Then we run:
azd up
This will ask you for any secrets or config that's required.
Once published you’ll be able to view your resources in the Azure Portal
You can also see the Aspire Dashboard in Azure and view your logs and traces
And traces:
Cleaning Up 🧹
While you’re playing around with Azure and Aspire don’t forget to remove resources if you’re not using them. Save yourself some money 🙂
azd down
Final Thoughts 💡
Hopefully this post has shown you how easy it is to get started with .NET Aspire. In time as Aspire gets more features I see this becoming a crucial tool in any developers tool belt. Being able to define your entire application platform in a type-safe language like C# is a huge step up from writing hard to read yaml files and managing large amounts of IaC files (bicep, terraform, etc.). It also greatly improves the local developer experience and streamlines onboarding new members to your team.
Stay tuned and remember to subscribe for more posts where we'll dive deeper into specific Aspire capabilities and continue to refine this demo app!
Let’s build something great together!
Chris
Subscribe so you don't miss out 🚀
Be the first to know about new blog posts, news, and more. Delivered straight to your inbox 📨
Related Posts
Using Aspire with Docker Hosts
05/24/2025
This guide shows how to deploy a multi-language app to any Docker host using .NET Aspire, making orchestration easy across different technologies.
Getting Started With Bicep
05/04/2025
Getting started with Bicep, Microsoft’s tool for writing clean, reusable Azure infrastructure as code, with practical examples and insights from real-world experience.
Why You Should Try .Net Aspire
05/03/2025
.NET Aspire is a powerful, flexible tool for modelling, developing, and observing cloud-native applications—making it worth exploring whether you’re a .NET developer or not.