Instruction file imported from Beschuetzer/test-templates-connector (
.github/instructions/net-aspire.instructions.md). Copyright stays with the author.
description: Instructions for setting up and using the .NET Aspire Agent. applyTo: **/.cs, **/.csproj
.NET Aspire Agent Instructions
Running .NET Aspire Applications in Development
These instructions are intended for coding agents (such as GitHub Copilot, Codex or similar tools) that need to run a .NET Aspire project locally during development and testing. Aspire’s AppHost is an orchestrator: it starts your application and its dependent services and remains running until you explicitly stop it. If you treat the host like a short‑lived build command and kill it prematurely, your tests or curl calls will fail. Follow the guidance below to ensure your agent runs Aspire solutions correctly.
1. Understand the AppHost lifecycle
AppHost runs until you stop it. When the entry point in the AppHost calls builder.Build().Run(), it starts all child services (projects, databases, caches, etc.) and then blocks the thread. The process does not exit on its own; it stays running until you send an interrupt (Ctrl +C). Microsoft’s quickstart confirms that to stop an Aspire app you must press Ctrl +C in the terminal【306692188975394†L0-L19】.
Running the AppHost is analogous to running npm run dev in a Node app: you start a long‑running process and then interact with it via HTTP or other protocols. Don’t expect the command to return immediately【306692188975394†L20-L24】.
2. Start the AppHost
Agents should use one of the following commands to run an Aspire application. Both commands build the AppHost, start the child services and launch the Aspire dashboard【306692188975394†L25-L39】:
Using the Aspire CLI (recommended for local development)
# Start the AppHost from the solution directory. This will block until you stop it.
aspire run --project <PathToYourAppHost.csproj>
# Add --watch if you want the app host to rebuild automatically on file changes.
aspire run --project <PathToYourAppHost.csproj> --watch
The run command builds and starts the AppHost, then displays each resource’s endpoints and opens the dashboard. It does not exit until you stop it. The CLI will error if it cannot find a unique AppHost in the current directory【306692188975394†L37-L40】.
Using dotnet run (when the Aspire CLI isn’t installed)
# Navigate to the AppHost project and run it directly.
dotnet run --project <PathToYourAppHost.csproj>
This uses the Aspire.AppHost.Sdk project to orchestrate your services. Just like the CLI, it will block until you interrupt it【306692188975394†L53-L57】.
Important agent behaviours
- Do not kill the AppHost prematurely. Agents must allow the AppHost process to keep running while performing tests. Do not send a SIGINT (Ctrl +C) or kill the process until all HTTP requests or verification steps have completed. The process prints endpoints (e.g.,
apiservice: http://localhost:xxxxx) once the services are ready. Wait for these endpoints before issuingcurlor test commands【306692188975394†L58-L67】. - Run tests and HTTP requests concurrently. Treat the AppHost as a background server. If your tool environment supports multiple terminals, run the AppHost in one terminal and execute
curlor other tests in another. In a single terminal environment, you can run the AppHost in the background (aspire run &) but remember to terminate it afterward【306692188975394†L68-L74】. - Stop the AppHost gracefully. After tests finish, send Ctrl +C to the terminal running the AppHost. This triggers a graceful shutdown so child services can clean up. The quickstart notes that pressing Ctrl +C is the proper way to stop the application【306692188975394†L75-L80】.
3. Integration testing with Aspire.Hosting.Testing
Aspire provides a testing package that allows you to start the AppHost inside your unit or integration tests without manual process management. This is the preferred way to run integration tests in code【306692188975394†L81-L85】:
- Install the package by referencing
Aspire.Hosting.Testingin your test project【306692188975394†L86-L87】. - Create and start the AppHost inside your test using
DistributedApplicationTestingBuilder. This builder launches your AppHost in a background thread and manages its lifecycle【306692188975394†L88-L92】. Example: - Do not add nuget packages to the test project that are already referenced by the AppHost, as this can lead to assembly conflicts.
using Aspire.Hosting;
using Aspire.Hosting.Testing;
using MyAspireSolution; // Contains the AppHost project class
[Fact]
public async Task WeatherEndpoint_ReturnsForecast()
{
// Create the distributed application for the AppHost.
await using var app = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyAspireSolution_AppHost>();
// Build and start all resources.
await app.BuildAsync();
await app.StartAsync();
// Wait for the API service to be running before making requests.
await app.ResourceNotificationService
.WaitForResourceAsync("apiservice", ResourceState.Running);
// Create an HttpClient for the API service; ports are resolved automatically.
var client = app.CreateHttpClient("apiservice");
var response = await client.GetAsync("/weather");
response.EnsureSuccessStatusCode();
// Dispose triggers a graceful shutdown of the AppHost and its services.
// Because app is declared with await using, this happens automatically.
}
In this pattern:
CreateAsync<TAppHost>()creates an application model for your AppHost. The testing builder randomizes ports to support parallel test runs【306692188975394†L125-L128】.app.BuildAsync()andapp.StartAsync()build and start the host and its resources【306692188975394†L129-L147】.app.ResourceNotificationService.WaitForResourceAsync("apiservice", ResourceState.Running)waits until the named service is ready【306692188975394†L150-L166】.app.CreateHttpClient("apiservice")returns an HttpClient preconfigured with the correct base address; do not hard‑code ports【306692188975394†L168-L172】.- Disposing
app(usingawait using) cleans up the AppHost processes automatically【306692188975394†L170-L174】.
This approach avoids manual Ctrl +C handling and ensures each test has an isolated instance of the AppHost【306692188975394†L175-L177】.
Basic Example from xUnit scaffolding template:
// Instructions:
// 1. Add a project reference to the target AppHost project, e.g.:
//
// <ItemGroup>
// <ProjectReference Include="../MyAspireApp.AppHost/MyAspireApp.AppHost.csproj" />
// </ItemGroup>
//
// 2. Uncomment the following example test and update 'Projects.MyAspireApp_AppHost' to match your AppHost project:
//
[Fact]
public async Task GetWebResourceRootReturnsOkStatusCode()
{
// Arrange
var cancellationToken = TestContext.Current.CancellationToken;
var appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.MyAspireApp_AppHost>(cancellationToken);
appHost.Services.AddLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Debug);
// Override the logging filters from the app's configuration
logging.AddFilter(appHost.Environment.ApplicationName, LogLevel.Debug);
logging.AddFilter("Aspire.", LogLevel.Debug);
// To output logs to the xUnit.net ITestOutputHelper, consider adding a package from https://www.nuget.org/packages?q=xunit+logging
});
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
await using var app = await appHost.BuildAsync(cancellationToken).WaitAsync(DefaultTimeout, cancellationToken);
await app.StartAsync(cancellationToken).WaitAsync(DefaultTimeout, cancellationToken);
// Act
using var httpClient = app.CreateHttpClient("webfrontend");
await app.ResourceNotifications.WaitForResourceHealthyAsync("webfrontend", cancellationToken).WaitAsync(DefaultTimeout, cancellationToken);
using var response = await httpClient.GetAsync("/", cancellationToken);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
4. Diagnostic tips for agents
- Check the Aspire dashboard. When the AppHost is running, the CLI launches a web‑based dashboard showing the state of each resource. Use this to confirm that services are running and to discover endpoint URLs【306692188975394†L178-L183】.
- Use logs. The dashboard’s Console and Structured views expose the logs from each service. If your agent sees failures, inspect logs there rather than assuming the process crashed【306692188975394†L184-L188】.
- Handle port randomization. In test mode, ports may be randomized. Use the dashboard or
app.CreateHttpClientrather than guessing the port【306692188975394†L188-L190】. - Don’t run partial solutions. Always run the AppHost project; do not attempt to start individual API or web projects separately unless you deliberately want to bypass Aspire’s orchestration【306692188975394†L191-L193】.
5. Summary
When running .NET Aspire during development or automated testing, agents must treat the AppHost as a long‑running server process. Start it with aspire run or dotnet run, wait until it reports ready endpoints, and keep it alive while performing any HTTP calls or tests【306692188975394†L195-L201】. For integration tests, prefer the Aspire.Hosting.Testing APIs to start and dispose of the AppHost programmatically【306692188975394†L198-L203】. Always stop the AppHost gracefully via Ctrl +C (or disposal) to allow resources to clean up and to avoid false negatives in your tests【306692188975394†L214-L216】.