In previous posts, we’ve seen how .NET Aspire can orchestrate multi-service setups — from running Python APIs to launching Vite frontends.
But Aspire can also do something more subtle and powerful: dynamically control how resources start and run — even with custom arguments at runtime.
This post demonstrates a minimal example showing how to build an Aspire interactive command that lets you input arguments on the fly before launching a console app.
Folder layout
Here’s the structure of this sample:
06_DynamicCMDSample/
├─ App/
│ └─ Program.cs
├─ AppHost/
│ └─ Program.cs
├─ ServiceDefaults/
│ └─ (default configuration)
└─ README.md
This layout follows the standard Aspire application template:
- App → a simple console project
- AppHost → the orchestration layer (the Aspire “brain”)
- ServiceDefaults → common defaults like logging and configuration
The console app (App/Program.cs)
Our example app just prints any arguments it receives and a friendly message:
foreach (var a in args)
{
Console.WriteLine(a);
}
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
You can test it standalone with:
dotnet run --project App -- arg1 arg2 arg3
Output:
arg1
arg2
arg3
Hello, World!
The Aspire AppHost (AppHost/Program.cs)
The real magic happens here.
We’ll use Aspire’s interactive commands and resource command services to let the user provide arguments dynamically at runtime — without touching the terminal.
#pragma warning disable ASPIREINTERACTION001
using Microsoft.Extensions.DependencyInjection;
var builder = DistributedApplication.CreateBuilder(args);
string[] projectArgs = [];
builder.AddProject<Projects.App>("myapp")
.WithExplicitStart()
.WithArgs(context =>
{
context.Args.Clear();
foreach (var arg in projectArgs)
{
context.Args.Add(arg);
}
})
.WithCommand("run", "Run with args", async context =>
{
var commandService = context.ServiceProvider.GetRequiredService<ResourceCommandService>();
var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();
var rns = context.ServiceProvider.GetRequiredService<ResourceNotificationService>();
var result = await interactionService.PromptInputAsync("Enter the arguments",
"Enter the arguments for the command to run",
new()
{
InputType = InputType.Text,
Label = "Arguments",
Placeholder = "arg1 arg2 arg3",
});
if (result.Canceled)
return CommandResults.Success();
projectArgs = result.Data.Value?.Split(' ', StringSplitOptions.RemoveEmptyEntries) ?? [];
if (rns.TryGetCurrentState(context.ResourceName, out var state)
&& state.Snapshot.State?.Text == KnownResourceStates.NotStarted)
{
return await commandService.ExecuteCommandAsync(context.ResourceName, "resource-start");
}
return await commandService.ExecuteCommandAsync(context.ResourceName, "resource-restart");
},
new()
{
IconName = "Play",
IconVariant = IconVariant.Regular,
IsHighlighted = true
});
builder.Build().Run();
#pragma warning restore ASPIREINTERACTION001
How it works
1. WithExplicitStart()
This tells Aspire not to automatically start the myapp project — we’ll control that manually via the command.
2. WithArgs(...)
When the app starts, Aspire passes along the currently stored projectArgs.
These arguments are dynamically updated when the user runs the custom command.
3. WithCommand("run", ...)
This defines a custom interactive command in Aspire’s dashboard.
When triggered:
- It opens a dialog asking for arguments.
- It stores those arguments in
projectArgs. - If the app isn’t running, it starts it with those arguments.
- If it’s already running, it restarts it.
The result: you can test the same app multiple times with different inputs — all from the Aspire dashboard UI.
Running the sample
To create everything from scratch:
dotnet new console -n App
dotnet new aspire-apphost -n AppHost
dotnet new aspire-servicedefaults -n ServiceDefaults
Then modify AppHost/Program.cs as shown above and reference your console project.
Finally, run:
dotnet run --project AppHost
Open the Aspire Dashboard, find the myapp resource, and click ▶ Run with args.
You’ll be prompted to enter arguments like:
foo bar baz
The console output will show:
foo
bar
baz
Hello, World!
…and you can repeat the process with different arguments without restarting Aspire itself.
Why this is useful
This simple pattern is incredibly flexible. You can use it to:
- Dynamically run CLI tools or microservices with different parameters
- Test various startup configurations without editing
appsettings.json - Prototype interactive workflows in Aspire for QA or developer demos
And since Aspire commands integrate directly into the dashboard UI, this feels like a natural, GUI-driven control panel for your distributed system.
With just a few lines of code, we built a dynamic, argument-driven command inside .NET Aspire.
This feature is still experimental, but it’s already opening exciting possibilities for:
- Parameterized launches
- Automated test runs
- Dev workflows that mix user input with resource control
Aspire isn’t just about spinning up containers — it’s about orchestrating intelligent workflows interactively.
That’s all folks!
Cheers!
Gašper Rupnik
{End.}

Leave a comment