Documentation
reference/aspire-hot-reload-and-dev-workflow.md
Aspire Hot Reload and Development Workflow
Last Updated: January 2025
Status: Current assessment of .NET Aspire capabilities
Related: Aspire overview
Overview
This document captures our analysis of hot reload and automatic restart capabilities in .NET Aspire for Dynaplex development. It documents what's currently possible, what isn't, and the trade-offs of various approaches.
The Developer Experience Vision
The ideal development workflow would:
- Start the AppHost once with all infrastructure running
- Make code changes to individual components
- Have only the changed component automatically rebuild and restart
- Infrastructure and other services remain running
- No full AppHost restart required
Current State of .NET Aspire (January 2025)
What Works Today
1. Hot Reload for Code Changes (Within Services)
.NET Hot Reload works within individual running services for many types of code changes:
- Method body changes
- Adding methods/properties to existing types
- Lambda expression changes
- Most Blazor UI changes
Limitation: When Hot Reload encounters "rude edits" (structural changes like adding interfaces, changing method signatures, etc.), it requires a full AppHost restart, not just the affected service.
2. Persistent Container Lifetimes (Infrastructure Persistence)
Aspire supports persistent container lifetimes for infrastructure resources:
var postgres = builder.AddPostgres("postgres")
.WithLifetime(ContainerLifetime.Persistent);
var redis = builder.AddRedis("cache")
.WithLifetime(ContainerLifetime.Persistent);
Benefit: Infrastructure containers (databases, caches, message queues) persist across AppHost restarts, dramatically reducing restart times.
Status in Dynaplex: ✅ Implemented across all infrastructure resources (see InfrastructureBuilder.cs and DynaplexInfrastructureExtensions.cs).
3. Run Without Debugging (Ctrl+F5 Workflow)
When running the AppHost with Ctrl+F5 (without debugger):
- Individual projects can be rebuilt independently
- Those projects restart automatically
- Infrastructure remains running
- Not fully automatic, but workable
4. dotnet watch on Individual Services
Can run dotnet watch directly on service projects for automatic rebuild/restart of that specific service while keeping other services running.
What Doesn't Work Today
1. Automatic Restart of Individual Services
When Hot Reload fails (rude edit), Aspire requires restarting the entire AppHost, not just the affected service.
GitHub Issues Tracking This:
- #7695: Only rebuild/restart impacted resources when hot reload cannot be used
- #295: Add support for restarting services from the dashboard
- #3095: Restart individual Aspire project
Status: Feature requests active as of January 2025, not yet implemented.
2. Manual Restart from Dashboard
Cannot manually stop/restart individual services from the Aspire Dashboard.
Status: Feature request #295.
3. Better dotnet watch Integration with AppHost
dotnet watch on the AppHost doesn't properly cascade to orchestrated services.
Status: Known issue #620.
Evaluated Alternatives
Container-Based Development
Concept: Package Dynaplex components as containers and use Aspire's container orchestration.
Potential Benefits
- More control over individual service lifecycles
- Could use persistent lifetimes for stable components
- Closer to production deployment model
- Volume mounts + watch modes for auto-rebuild
Significant Drawbacks
- Slower build loop (container image building is slower than .NET builds)
- More complex debugging (debugging inside containers is harder)
- Less integrated with .NET tooling (lose seamless IDE integration)
- Requires significant changes to development workflow
- Moves away from Aspire's strengths for .NET development
Decision: Not pursuing at this time. The drawbacks outweigh the benefits for our current workflow.
Current Dynaplex Approach
What We've Implemented
1. Persistent Infrastructure Lifetimes
All infrastructure resources use ContainerLifetime.Persistent:
- PostgreSQL database
- Azure App Configuration emulator
- Azurite (blob storage emulator)
- Redis (for Superset analytics)
- Superset analytics container
Impact: Infrastructure no longer restarts between AppHost sessions. This is the single biggest improvement to restart times.
Location:
strata/orchestration/src/Acsis.Dynaplex.Strata.Orchestration/InfrastructureBuilder.csstrata/orchestration/src/Acsis.Dynaplex.Strata.Orchestration/DynaplexInfrastructureExtensions.cs
2. Project-Based Service Orchestration
Component services remain as AddProject resources (not containers):
- Maintains excellent debugging experience
- Seamless IDE integration
- Fast compilation
- Full .NET tooling support
Recommended Workflows
For Minor Changes (Hot Reload Compatible)
- Start AppHost normally (F5)
- Make code changes
- Hot Reload applies automatically
- Test changes immediately
Best for: Method implementations, UI tweaks, lambda expressions
For Structural Changes (Rude Edits)
- Run AppHost with Ctrl+F5 (no debugger)
- Make structural changes
- Rebuild affected project
- Project restarts automatically
- Infrastructure and other services remain running
Best for: Adding interfaces, changing signatures, adding dependencies
For Heavy Refactoring
- Accept that full restart is needed
- Infrastructure will persist (fast restart)
- Only component services need to reinitialize
Best for: Multi-component changes, dependency updates
Performance Characteristics
Without Persistent Containers
- Full restart: 30-60 seconds (cold start)
- Infrastructure initialization: 20-40 seconds
- Service startup: 10-20 seconds
With Persistent Containers (Current)
- Full restart: 10-20 seconds (warm start)
- Infrastructure initialization: 0 seconds (already running)
- Service startup: 10-20 seconds
Improvement: ~50-70% reduction in restart time
Future Outlook
The Aspire team is aware of the need for individual service restart capabilities. Based on community engagement on GitHub issues, this is likely to be implemented in future versions.
Expected Future Capabilities
- Dashboard controls to stop/start individual services
- Automatic detection of which services need restart
- More granular watch and reload capabilities
- Better integration with
dotnet watch
What This Means for Dynaplex
When these features arrive, we'll be able to:
- Keep infrastructure running (we already do this)
- Selectively restart only changed services (new capability)
- Have a truly seamless hot reload experience
Our current architecture (project-based services + persistent infrastructure) positions us well to take advantage of these features when they become available.
Guidance for Developers
Structure Your Work Sessions
- Hot-reloadable work: Group method implementation, UI tweaks, and logic changes
- Structural work: Batch interface additions, signature changes, and dependency updates
- Heavy refactoring: Accept that restart is needed, rely on fast infrastructure persistence
Optimize for Hot Reload Success
- Avoid structural changes during active debugging sessions
- Use partial classes to separate hot-changeable code from structural code
- Commit structural changes when you're willing to do a restart
Take Advantage of Persistent Infrastructure
- Don't manually stop containers between sessions
- Infrastructure accumulates state (databases, caches) naturally
- Clean up only when needed:
docker container pruneorpodman container prune
Cleanup Commands
List Persistent Containers
docker ps -a --filter "name=postgres"
docker ps -a --filter "name=redis"
docker ps -a --filter "name=azurite"
docker ps -a --filter "name=config"
docker ps -a --filter "name=superset"
Remove Persistent Containers (when needed)
docker stop postgres redis azurite config superset
docker rm postgres redis azurite config superset
Or with Podman:
podman stop postgres redis azurite config superset
podman rm postgres redis azurite config superset
References
- .NET Aspire Overview
- Aspire Orchestration Overview
- Persistent Container Lifetimes
- .NET Hot Reload
- dotnet watch
GitHub Issues
- #7695: Only rebuild/restart impacted resources
- #295: Add support for restarting services from dashboard
- #3095: Restart individual Aspire project
- #620: dotnet watch on AppHost doesn't cascade to services
Conclusion: Our current approach (persistent infrastructure + project-based services) provides excellent developer experience today while positioning us to take advantage of future Aspire enhancements. The container-based alternative has been evaluated and rejected due to significant drawbacks that outweigh its benefits for our .NET-focused development workflow.