Skip to content

Working with Aspire

davidkallesen edited this page Apr 15, 2026 · 1 revision

☁️ Working with .NET Aspire

This guide explains how to use the generated API with .NET Aspire for local development orchestration.

🌟 Overview

.NET Aspire provides a development-time orchestrator that manages service startup, health monitoring, environment variable injection, and service discovery. When combined with the source generator, you get a fully orchestrated stack from a single dotnet run.

πŸ“‚ Project Structure

A typical Aspire-orchestrated solution:

MyApi/
β”œβ”€β”€ MyApi.Aspire/              # Aspire AppHost (orchestrator)
β”‚   β”œβ”€β”€ Program.cs
β”‚   └── MyApi.Aspire.csproj
β”œβ”€β”€ MyApi.Api/                 # ASP.NET Core API
β”‚   └── Program.cs
β”œβ”€β”€ MyApi.Api.Contracts/       # Generated code (source generator)
β”‚   β”œβ”€β”€ .atc-rest-api-server
β”‚   └── MyApi.yaml
β”œβ”€β”€ MyApi.Api.Domain/          # Handler implementations
β”‚   └── Handlers/
β”œβ”€β”€ MyApi.ClientApp/           # Console/test client (optional)
β”‚   └── .atc-rest-api-client
└── MyApi.BlazorApp/           # Blazor frontend (optional)

πŸ”§ Setting Up the AppHost

1. Create the Aspire Project

# Using the CLI scaffolding
atc-rest-api-gen generate server \
  -s api.yaml \
  -o src/ \
  --aspire

# Or manually add the project
dotnet new aspire-apphost -n MyApi.Aspire

2. AppHost Program.cs

var builder = DistributedApplication.CreateBuilder(args);

// Add the API project
var api = builder
    .AddProject<Projects.MyApi_Api>("api");

// Add a console client that references the API
builder
    .AddProject<Projects.MyApi_ClientApp>("client")
    .WithReference(api.GetEndpoint("http"))
    .WaitFor(api);

// Add a Blazor frontend
builder
    .AddProject<Projects.MyApi_BlazorApp>("blazor")
    .WithReference(api.GetEndpoint("http"))
    .WaitFor(api)
    .WithExternalHttpEndpoints();

await builder.Build().RunAsync();

3. AppHost .csproj

<Project Sdk="Aspire.AppHost.Sdk/13.1.2">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\MyApi.Api\MyApi.Api.csproj" />
    <ProjectReference Include="..\MyApi.ClientApp\MyApi.ClientApp.csproj" />
    <ProjectReference Include="..\MyApi.BlazorApp\MyApi.BlazorApp.csproj" />
  </ItemGroup>
</Project>

πŸ” Service Discovery

Aspire injects service URLs via environment variables. Use them in your client projects:

Console Client

var builder = Host.CreateApplicationBuilder(args);

// Aspire injects the API URL as an environment variable
var apiBaseUrl = builder.Configuration["services:api:http:0"]
    ?? "https://localhost:5001";

builder.Services.AddHttpClient<MyApiClient>(client =>
{
    client.BaseAddress = new Uri(apiBaseUrl);
});

Blazor Client

var builder = WebAssemblyHostBuilder.CreateDefault(args);

// The API URL is injected by Aspire's WithReference()
var apiBaseUrl = builder.Configuration["services:api:http:0"]
    ?? builder.HostEnvironment.BaseAddress;

builder.Services.AddHttpClient<MyApiClient>(client =>
{
    client.BaseAddress = new Uri(apiBaseUrl);
});

React/Vite Client

For JavaScript frontends, Aspire can inject environment variables via AddViteApp:

// In AppHost Program.cs
builder
    .AddViteApp("react-app", "../MyApi.ReactApp")
    .WithEnvironment("VITE_API_BASE_URL", api.GetEndpoint("http"))
    .WaitFor(api)
    .WithExternalHttpEndpoints();

Then in your React app:

import { ApiProvider } from './api/hooks/ApiProvider';

const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:5000';

function App() {
  return (
    <ApiProvider baseUrl={apiBaseUrl}>
      <YourApp />
    </ApiProvider>
  );
}

🏷️ Using Constants.HttpClientName

When using EndpointPerOperation mode, the generated Constants.HttpClientName integrates with Aspire's service discovery:

// In your client project's Program.cs
builder.Services
    .AddHttpClient(
        MyApi.Generated.Constants.HttpClientName,
        client =>
        {
            client.BaseAddress = new Uri(apiBaseUrl);
        });

πŸš€ Running the Stack

# Start everything with Aspire
cd MyApi.Aspire
dotnet run

# The Aspire dashboard opens at https://localhost:15888
# - API:     https://localhost:{dynamic-port}
# - Client:  runs and calls API
# - Blazor:  https://localhost:{dynamic-port}

The Aspire dashboard shows:

  • Service health and status
  • Distributed traces across services
  • Structured logs from all projects
  • Environment variables and endpoints

⏳ WaitFor Dependencies

Use WaitFor() to ensure services start in the correct order:

// Client waits for API to be healthy before starting
builder
    .AddProject<Projects.MyApi_ClientApp>("client")
    .WithReference(api.GetEndpoint("http"))
    .WaitFor(api);

This prevents the client from failing on startup because the API isn't ready yet.

πŸ“¦ Sample Projects

The repository includes two Aspire-enabled samples:

Sample Description
Showcase Full-featured: API + Blazor + Console client + React app with Aspire orchestration
PetStoreFull Simple: API + Aspire AppHost for basic orchestration

Run the Showcase sample:

cd sample/Showcase/Showcase.Aspire
dotnet run

πŸ’‘ Tips

  • Use WithExternalHttpEndpoints() for browser-accessible services (Blazor, React)
  • Aspire assigns dynamic ports β€” always use service discovery, not hardcoded URLs
  • Add launchSettings.json with "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" for HTTP-only development
  • The --aspire flag in the CLI scaffolding creates the AppHost project automatically

➑️ Next Steps

🏠 Home

πŸ’Ό Why This Tool?

πŸ“– Getting Started

βš™οΈ Features

🌐 Frontend

πŸ“‹ Reference


πŸ”— Resources

Clone this wiki locally