Introduction
When developers build distributed applications, the AppHost usually takes care of starting services, connecting resources, and making the local development environment easier to manage.
But real applications often need more than that.
Sometimes a developer needs to upload a configuration file, confirm a destructive operation, enter a value, see progress while a long-running operation is executing, or receive a useful message when something goes wrong.
This is where the Interaction Service in .NET Aspire 13.5 becomes interesting.
Aspire 13.5 expands the AppHost interaction capabilities with file inputs, progress dialogs, command arguments, and other interaction features. The result is that the AppHost can behave less like a simple application launcher and more like an interactive development experience.
For developers working with distributed .NET applications, this can make setup, import, debugging, and development workflows much easier to build into the application itself.
What Is the Aspire Interaction Service?
The Interaction Service is exposed through IInteractionService and allows an Aspire application to interact with the developer.
Depending on how the application is running, the interaction can appear in the Aspire dashboard or through the CLI.
For example:
Aspire AppHost
|
v
Interaction Service
|
+------> Dashboard Dialog
|
+------> Dashboard Notification
|
+------> User Input
|
+------> CLI Input
|
v
Application Continues
The service can be used to:
Ask the developer for input
Request confirmation
Display notifications
Display message boxes
Support command-driven workflows
Collect files
Report progress for longer operations
Microsoft's documentation describes the interaction service as a way to prompt users for input, request confirmation, and display messages in Aspire applications.
Why Interactive AppHosts Matter
Consider a common local development scenario.
A developer clones a distributed application and needs to import some configuration before starting work.
Without an interactive AppHost, the instructions might look like this:
1. Download configuration.json
2. Copy it into a specific folder
3. Rename the file
4. Run a setup script
5. Start Aspire
6. Check whether the import succeeded
This works, but the developer has to understand several implementation details before they can even start the application.
With an interactive resource command, the workflow can become:
1. Start Aspire
2. Click "Import Configuration"
3. Select configuration.json
4. Aspire validates the file
5. Import starts
6. Progress is displayed
7. Result is shown
The important difference is that the workflow becomes part of the application's development experience.
Getting the Interaction Service
The service can be resolved from dependency injection.
A simplified example looks like this:
var interactionService =
serviceProvider.GetRequiredService<IInteractionService>();
if (interactionService.IsAvailable)
{
var result = await interactionService.PromptInputAsync(
title: "Environment Configuration",
message: "Enter the environment name.");
var environment = result.Data;
}
The IsAvailable check is important.
The interaction service is not available in every execution context. Microsoft specifically recommends checking IInteractionService.IsAvailable before using dashboard-only interactions because attempting to use an unavailable interaction can result in an exception.
Dashboard and CLI Behavior
One of the useful parts of the Interaction Service is that Aspire understands different execution environments.
There are two important contexts:
| Context | Typical Usage | Interaction |
|---|
| Aspire Dashboard | Local development | Dialogs, notifications, forms |
| Aspire CLI | Publish/deploy workflows | Text-based input |
For example, input prompts can work in both environments:
Dashboard:
+------------------------------+
| Environment Name |
| |
| [ Development ] |
| |
| [ Continue ] |
+------------------------------+
While the CLI can provide an equivalent text prompt.
However, not every interaction is available in the CLI. According to the current documentation, PromptInputAsync and PromptInputsAsync are supported for CLI operations such as aspire publish and aspire deploy, while message boxes, notifications, and confirmation dialogs are dashboard-only.
This distinction is important when designing reusable AppHost workflows.
Asking for User Input
The Interaction Service supports different input types.
Examples include:
Text
Secret text
Choice
Boolean
Number
A simple example is asking for a service URL:
var result = await interactionService.PromptInputAsync(
title: "External Service",
message: "Enter the external service URL.");
var serviceUrl = result.Data;
For multiple inputs, you can collect several values together.
For example:
Application Name
[ Orders API ]
Environment
[ Development ]
Port
[ 5001 ]
This is much cleaner than requiring developers to manually edit configuration files.
Each interaction input has a programmatic Name and a user-facing Label. The name is used to retrieve the value programmatically, while the label is displayed to the developer.
Using Confirmation Dialogs
Confirmation prompts are particularly useful for operations that could cause data loss.
Imagine an Aspire resource command that resets a local database.
Instead of immediately executing the operation:
await ResetDatabaseAsync();
the workflow can first ask for confirmation:
var confirmation =
await interactionService.PromptConfirmationAsync(
title: "Reset Database",
message: "Are you sure you want to reset the development database?");
if (confirmation.Data)
{
await ResetDatabaseAsync();
}
This creates a simple safety boundary.
User clicks "Reset"
|
v
Confirmation Dialog
|
+---- Cancel ----> Stop
|
+---- Confirm ---> Reset Database
This pattern is especially useful for destructive developer operations.
Microsoft recommends confirmation prompts for operations that cannot easily be undone.
Adding Interactions to Resource Commands
The Interaction Service becomes especially useful when combined with custom resource commands.
Imagine an Aspire application with a database resource:
Resources
Orders API
Inventory API
PostgreSQL
Redis
PostgreSQL
[Reset Database]
When the developer selects Reset Database, the command can ask for confirmation before performing the operation.
A simplified AppHost structure might look like:
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres");
var database = postgres.AddDatabase("ordersdb");
// Resource command logic can use the interaction service
// to collect input or confirm an operation.
var app = builder.AddProject<Projects.OrdersApi>("orders-api")
.WithReference(database);
builder.Build().Run();
The exact command registration depends on the resource and Aspire APIs being used, but the architectural idea is straightforward: the AppHost can expose developer operations directly through the Aspire dashboard.
File Inputs in Aspire 13.5
One of the more practical additions in Aspire 13.5 is file input support for resource commands.
Before this capability, a developer might need to place a file into a predefined directory before running a setup operation.
Now an interactive command can request the file directly.
For example:
Resource: Orders API
Command:
Import Configuration
Select configuration file:
[ config.json ]
File type:
JSON / YAML
[ Import ]
The AppHost can then receive the uploaded file and process it.
This is particularly useful for:
Microsoft's 13.5 release notes specifically describe a file-import workflow where a resource command can open a file picker, restrict accepted file types, enforce a size limit, and provide the file as a stream to the AppHost.
Designing a File Import Workflow
A practical file-import flow should validate the file before processing it.
For example:
public async Task ImportConfigurationAsync(Stream file)
{
using var reader = new StreamReader(file);
var json = await reader.ReadToEndAsync();
if (string.IsNullOrWhiteSpace(json))
{
throw new InvalidOperationException(
"The configuration file is empty.");
}
// Deserialize and validate configuration here.
}
The important production consideration is that file upload does not mean the file should automatically be trusted.
Validate:
The interaction layer improves the user experience, but application-level validation is still required.
Progress Dialogs for Long-Running Operations
Some operations take more than a few seconds.
For example:
Import database
|
+--> Validate file
+--> Read records
+--> Transform data
+--> Insert records
+--> Validate import
|
v
Complete
A progress dialog can provide feedback while the operation is running.
Conceptually:
Importing data...
[###############-------] 72%
Processed: 7,200 / 10,000
[ Cancel ]
This is useful because the developer can distinguish between an operation that is still working and one that has stopped responding.
Aspire 13.5 adds progress dialog support, including optional cancellation. Microsoft currently identifies the progress-dialog API as experimental in this release and associates it with the ASPIREINTERACTION001 diagnostic.
That means teams should treat this API differently from stable interaction APIs and expect its usage details to evolve.
Command Arguments Can Be Better Than Prompts
Not every interaction should use IInteractionService.
Aspire's documentation specifically recommends command arguments when the goal is simply to collect input for a custom resource command.
Why?
Because command arguments can work in both the dashboard and CLI.
For example:
Dashboard:
Import Configuration
File: [ config.json ]
CLI:
aspire ... --file config.json
This gives the same underlying command a more automation-friendly interface.
A useful rule is:
| Requirement | Better Approach |
|---|
| Ask a question in dashboard | Interaction Service |
| Confirm destructive dashboard action | Interaction Service |
| Collect reusable command input | Command arguments |
| Support dashboard + CLI input | Command arguments |
| Show dashboard notification | Interaction Service |
| File selection | File input API |
| Long-running dashboard operation | Progress dialog |
The goal is not to use the Interaction Service everywhere. Use the simplest mechanism that fits the workflow.
Handling CLI Limitations
A common mistake is assuming that every dashboard interaction will automatically work from the CLI.
For example:
await interactionService.PromptConfirmationAsync(...);
is not suitable for CLI execution.
The current documentation states that confirmation, notification, and message-box methods can throw when used during CLI operations such as aspire publish or aspire deploy.
A safer pattern is:
if (interactionService.IsAvailable)
{
var confirmation =
await interactionService.PromptConfirmationAsync(
title: "Confirm",
message: "Continue with the operation?");
if (!confirmation.Data)
{
return;
}
}
else
{
// Provide a non-interactive fallback.
}
The exact fallback depends on the operation, but the important design principle is to avoid assuming that an interactive dashboard is always available.
Advantages
Better Developer Experience
Instead of asking developers to memorize setup scripts and file locations, the AppHost can guide them through the workflow.
Fewer Manual Setup Steps
Configuration imports and resource operations can happen directly from the Aspire dashboard.
Safer Destructive Operations
Confirmation dialogs provide a useful safety barrier for operations such as resetting local databases.
Better Feedback
Notifications and progress indicators make longer-running operations easier to understand.
More Flexible Resource Commands
Resource commands can become small developer tools that are directly connected to the resources they operate on.
Disadvantages and Limitations
Some APIs Are Experimental
Not every interaction feature in Aspire 13.5 is stable. Progress dialogs and terminal-related functionality are identified as experimental in the 13.5 release.
Dashboard and CLI Are Not Identical
Developers need to design workflows around the capabilities available in each execution context.
More AppHost Code
Interactive workflows add logic to the AppHost. Poorly designed interactions can make the AppHost harder to understand.
Input Still Requires Validation
A file picker or input form improves UX, but it does not validate that the supplied value is correct or safe.
Not Every Operation Needs a UI
Simple configuration values may be better represented as parameters or command arguments instead of custom interaction dialogs.
Common Mistakes
Ignoring IsAvailable
Do not assume the interaction service is always available.
if (interactionService.IsAvailable)
{
// Interactive operation
}
This becomes especially important when the same AppHost supports both dashboard and CLI workflows.
Using UI Prompts for Everything
If a value is naturally a command argument, use a command argument instead.
Forgetting Cancellation
Long-running operations should consider cancellation where the API supports it.
Trusting Uploaded Files
Always validate uploaded files before processing them.
Making the AppHost Too Complicated
Interaction logic should support the developer workflow rather than turning the AppHost into a large application containing unrelated business logic.
Troubleshooting
| Problem | What to Check |
|---|
| Interaction throws an exception | Check IInteractionService.IsAvailable |
| Prompt works locally but fails in CLI | Verify whether that interaction supports CLI |
| File import fails | Check file type, size, stream handling, and validation |
| Command input is awkward | Consider command arguments |
| Progress API produces warnings | Check the experimental ASPIREINTERACTION001 diagnostic |
| User cannot see notification | Verify the application is running in dashboard context |
| Destructive command runs immediately | Add a confirmation step |
| Configuration value is missing | Check input names and result lookup |
Best Practices
Keep Interactions Small
A good interaction should ask for exactly what is needed.
Instead of:
Enter all application configuration.
prefer several clearly named values or a configuration-file import.
Validate Before Processing
Do not assume that user input is correct.
if (string.IsNullOrWhiteSpace(environment))
{
throw new InvalidOperationException(
"Environment is required.");
}
Prefer Command Arguments for Reusable Commands
If the same command needs to work in the dashboard and CLI, command arguments are often a better choice than dashboard-only prompts.
Confirm Destructive Actions
Database resets, cleanup operations, and similar actions should require deliberate confirmation.
Keep Business Logic Outside the Interaction Layer
The interaction should collect input or provide feedback. The actual application logic should remain in appropriately designed services.
Conclusion
.NET Aspire 13.5 makes the local distributed application experience feel more interactive. Instead of treating the AppHost as something that only starts APIs, databases, and other resources, developers can now use it to build useful workflows around those resources. File uploads, input prompts, confirmations, notifications, and progress feedback can remove a lot of small setup steps that developers normally handle manually. The main thing to remember is that these features should be used thoughtfully. Check whether the interaction works in the dashboard or CLI, validate every input, use command arguments when they make more sense, and be careful with experimental APIs. When used this way, the Interaction Service can make an Aspire-based project easier to set up, easier to test, and much nicer to work with day to day.