Introduction
Setting up a distributed application can involve a surprising number of small manual steps.
A developer may need to import a configuration file, load test data, provide a certificate, select a local settings file, or upload a fixture before a service can start working correctly.
Usually, these tasks are documented as instructions:
1. Find the file.
2. Copy it to a specific folder.
3. Rename it.
4. Start the application.
5. Run the import command.
The process works, but it puts the responsibility on the developer to know exactly what to do.
.NET Aspire 13.5 introduces file-input support for interactive resource commands. This allows an Aspire application to request a file directly through the dashboard, apply restrictions such as file type and size, and pass the selected file to the AppHost for processing. Microsoft specifically highlights file import as one of the new interaction capabilities in Aspire 13.5.
This is a small feature, but it can make a noticeable difference to developer experience because setup operations can become part of the application rather than a separate collection of manual instructions.
What Are Aspire File Inputs?
File inputs allow a custom Aspire resource command to ask the developer to select a file.
The basic workflow is:
Aspire Dashboard
|
v
Resource Command
|
v
File Picker
|
v
Developer Selects File
|
v
AppHost Receives File
|
v
Validate
|
v
Process
|
v
Show Result
For example, a developer could select:
config.json
from the dashboard and have the AppHost import it.
The feature is especially useful for development-time workflows where manually copying files is inconvenient.
Why File Inputs Are Useful
Consider a distributed application with:
Orders API
Inventory API
Payments API
PostgreSQL
Redis
A developer wants to load sample inventory data.
Without an interactive file input:
Download sample-data.json
|
v
Find local project directory
|
v
Copy file
|
v
Run import command
|
v
Check logs
With a dashboard command:
Inventory API
|
+-- Import Sample Data
|
v
Select File
|
v
Validate
|
v
Import
The second workflow is easier to discover, especially for developers who are new to the repository.
File Inputs Are a Development Experience Feature
It is important to understand where this capability fits.
The file-input API is primarily useful for development-time and AppHost workflows.
It does not mean an ASP.NET Core application should expose arbitrary filesystem access through a web interface.
The intended model is closer to:
Developer
|
v
Aspire Dashboard
|
v
AppHost Interaction
|
v
Development Resource
rather than:
Internet User
|
v
Upload API
|
v
Production File System
That distinction matters for security and architecture.
A Typical File Import Scenario
Imagine an application that needs a local JSON configuration file.
The desired user experience could be:
+--------------------------------------+
| Import Configuration |
| |
| Select configuration file |
| |
| [ Choose File ] |
| |
| Accepted: .json |
| Maximum size: 5 MB |
| |
| [ Import ] |
+--------------------------------------+
After the user selects the file:
File
|
v
Read Stream
|
v
Validate Size
|
v
Validate Format
|
v
Parse JSON
|
v
Validate Schema
|
v
Apply Configuration
The important part is that file selection is only the first step.
The application still needs to validate the content.
File Type Restrictions
A useful file-input workflow should restrict the files that developers can select.
For example:
Accepted files:
.json
.yaml
.yml
If the workflow only expects JSON, there is little reason to allow every file type.
Conceptually:
Allowed:
config.json
Rejected:
image.png
archive.zip
unknown.exe
This improves the user experience and reduces accidental input.
However, file extension filtering is not a security boundary.
A malicious or incorrect file can still have a misleading extension.
The application should inspect and validate the actual content.
File Size Limits
File size should also be controlled.
Suppose the workflow only needs a small configuration file.
A sensible limit might be:
Maximum:
5 MB
The exact limit depends on the workflow.
The reason is simple: an interactive file upload should not allow an accidentally huge file to consume unnecessary memory, disk space, or processing time.
A robust processing pipeline is:
Selected File
|
v
Size Check
|
+---- Too Large ----> Reject
|
v
Format Check
|
+---- Invalid ------> Reject
|
v
Content Validation
|
+---- Invalid ------> Reject
|
v
Process
Microsoft's Aspire 13.5 release notes specifically describe file-input capabilities that include file-type restrictions and maximum file-size limits.
Working With the Uploaded File
The AppHost receives the selected file as a stream.
A simplified processing method could look like:
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.");
}
// Parse and validate the configuration.
}
The important point is to process the stream rather than assuming that the file already exists somewhere on the developer's machine.
The AppHost becomes responsible for handling the file received from the interaction.
Deserialize Only After Validation
Suppose the expected configuration looks like:
{
"environment": "Development",
"apiBaseUrl": "https://localhost:5001",
"enableSeedData": true
}
A corresponding model might be:
public sealed class AppConfiguration
{
public string Environment { get; set; } = string.Empty;
public string ApiBaseUrl { get; set; } = string.Empty;
public bool EnableSeedData { get; set; }
}
The file can then be deserialized:
var configuration =
JsonSerializer.Deserialize<AppConfiguration>(
json);
if (configuration is null)
{
throw new InvalidOperationException(
"Invalid configuration.");
}
But deserialization alone is not validation.
You should still verify required values:
if (string.IsNullOrWhiteSpace(configuration.Environment))
{
throw new InvalidOperationException(
"Environment is required.");
}
if (string.IsNullOrWhiteSpace(configuration.ApiBaseUrl))
{
throw new InvalidOperationException(
"API base URL is required.");
}
This prevents an apparently valid JSON document from becoming invalid application state.
File Inputs and Configuration Import
One practical use case is importing local environment configuration.
For example:
Development
|
+-- appsettings.json
+-- appsettings.Development.json
+-- local-secrets.json
Instead of asking every developer to manually copy these files, Aspire can provide an explicit import workflow.
The command could be:
Orders API
|
+-- Import Local Configuration
The developer selects the file.
The AppHost validates it.
The application then receives the required development configuration.
This can make onboarding considerably easier.
File Inputs and Test Data
Another useful scenario is loading test data.
Imagine an e-commerce application that needs a large product dataset for local development.
The file could contain:
{
"products": [
{
"name": "Laptop",
"price": 1200
},
{
"name": "Keyboard",
"price": 80
}
]
}
The workflow becomes:
Select products.json
|
v
Validate JSON
|
v
Validate Product Schema
|
v
Insert Test Data
|
v
Show Import Result
This is much easier than asking developers to learn a database import command before they can start testing the application.
Showing Import Progress
File imports can take time.
For example:
products.json
|
v
10,000 records
|
v
Validate
|
v
Transform
|
v
Insert
A progress workflow can make the operation easier to understand.
Conceptually:
Importing products...
[############--------] 63%
6,300 / 10,000 records
Aspire 13.5 also adds progress-dialog support to the Interaction Service. Microsoft identifies the progress-dialog functionality as experimental in this release, so teams should evaluate it carefully before depending on it as a stable API.
File Inputs vs Command-Line Arguments
Developers sometimes need to decide whether a workflow should use a file picker or a command-line argument.
Both can be useful.
Join the conversation! Your thoughts help the community grow.