WithLaunchSettings() extension to override or create a launch profile
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
>Disclaimer: AI was used to compose a good coherent proposal with sources from code examples and the general idea description for the API.
## Background and Motivation
This is intended to solve a simple problem: `launchSettings.json` are often "optimized" for working with a single app/microservice in isolation, and so having the ability to override or set the settings for each project in a type-safe manner would allow a much better developer experience.
Launch profiles drive Aspire’s local orchestration: they decide URLs, env-vars, debug flags, and whether `dotnet watch` is used ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/launch-profiles)][1]).
Today the only API surface is `launchProfileName` on `AddProject`, which merely picks a profile and copies a handful of fields ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.projectresourcebuilderextensions.addproject?view=dotnet-aspire-9.0)][2]). Features such as hot-reload, alternate executables, or ad-hoc env-vars still require hand-editing JSON, breaking Aspire’s “configure everything in code” ethos ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/app-host-overview?utm_source=chatgpt.com)][3], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview?utm_source=chatgpt.com)][4]).
A fluent `WithLaunchSettings` delegate mirrors existing builder hooks like `WithEndpoint`, `WithEnvironment`, `WithArgs`, and `WithReplicas` ([[apisof.net](https://apisof.net/catalog/8727891aef3d4a57985d393ded635fe5?fx=net46)][5], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withenvironment?view=dotnet-aspire-9.0)][6], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withargs?view=dotnet-aspire-9.0)][7], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.projectresourcebuilderextensions.withreplicas?view=dotnet-aspire-9.2&utm_source=chatgpt.com)][8], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withendpoint?view=dotnet-aspire-9.0&utm_source=chatgpt.com)][9]) while letting developers compose or mutate launch properties programmatically.
---
## Proposed API
```diff
file-scoped namespace Aspire.Hosting;
public static class ResourceBuilderLaunchSettingsExtensions
{
+ /// Mutate or create the effective launch profile for a project resource.
+ public static IResourceBuilder WithLaunchSettings(
+ this IResourceBuilder builder,
+ Action configure);
}
public sealed class LaunchProfileBuilder
{
// Fluent modifiers – return 'this' for chaining
public LaunchProfileBuilder Profile(string name);
public LaunchProfileBuilder ApplicationUrl(string url);
public LaunchProfileBuilder CommandLineArgs(string args);
public LaunchProfileBuilder ExecutablePath(string path);
public LaunchProfileBuilder WorkingDirectory(string path);
public LaunchProfileBuilder Environment(string key, string value);
public LaunchProfileBuilder DotNetArguments(string args);
// Additional members map 1-to-1 with launchSettings.json when needed
}
```
* Restriction to **`ProjectResource`** ensures compile-time safety; launch settings are a .NET-specific construct ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.applicationmodel.projectresource?view=dotnet-aspire-8.0)][10]).
* Implementation simply appends a `LaunchProfileAnnotation` to the in-memory model, similar to how `WithEndpoint` or `WithEnvironment` append their annotations ([[apisof.net](https://apisof.net/catalog/8727891aef3d4a57985d393ded635fe5?fx=net46)][5], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withenvironment?view=dotnet-aspire-9.0)][6]).
---
## Usage Examples
```csharp
var api = builder
.AddProject("api")
.WithLaunchSettings(ls => ls
.Profile("https")
.ExecutablePath("dotnet")
.CommandLineArgs("watch run")
.ApplicationUrl("https://localhost:5050")
.Environment("ASPNETCORE_ENVIRONMENT", "Development"));
var frontend = builder
.AddProject("frontend")
.WithLaunchSettings(ls => ls
.Profile("dev")
.CommandLineArgs("npm run dev")
.WorkingDirectory("../frontend")
.Environment("PORT", "0")) // Aspire patches actual port
.WaitFor(api)
.WithReference(api);
```
The pattern looks and feels identical to other Aspire builder helpers, so existing muscle memory applies ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withargs?view=dotnet-aspire-9.0)][7], [[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withendpoint?view=dotnet-aspire-9.0&utm_source=chatgpt.com)][9]).
---
## Alternative Designs
| Option | Why Rejected |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| **Parameter-only** `WithLaunchSettings(string profile)` | Duplicates `launchProfileName`; still forces JSON edits for everything else. |
| **Raw-JSON overload** | Loses IntelliSense and static validation; violates SRP. |
| **MSBuild property injection** | Requires rebuilds for every tweak, slowing the inner loop Aspire optimises ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/launch-profiles)][1]). |
---
## Implementation sketch
The extension should mimic the existing *annotation* pattern used by Aspire’s other fluent helpers. Inside `WithLaunchSettings` you:
1. Call `builder.GetOrAddAnnotation()` (same helper used by `WithEndpoint` to create/update endpoint metadata) to obtain the current launch-profile payload or create a new one. ([learn.microsoft.com][11])
2. Wrap that payload in a lightweight `LaunchProfileBuilder` that simply forwards each fluent call (`ApplicationUrl`, `Environment`, …) to set properties on the underlying annotation object, mirroring the fields documented for launch profiles. ([learn.microsoft.com][12])
3. Invoke the user-supplied delegate so callers can chain mutations, then return the original `IResourceBuilder` for further DSL composition. This parallels the design of `WithEnvironment`, ensuring deferred execution until the app-model is serialized. ([learn.microsoft.com][13])
4. At build time the orchestrator already reads `LaunchProfileAnnotation` when it wires up process start-info, so no additional runtime code is needed—the new annotation just slots into that pipeline. ([learn.microsoft.com][14])
Because the method is an extension on `IResourceBuilder` it compiles for every project resource yet stays invisible to containers, in exactly the same way that `WithReplicas` scopes itself. ([learn.microsoft.com][15])
---
## Risks
* **API surface creep** – adds a new builder type, but aligns with existing extension-method pattern ([[apisof.net](https://apisof.net/catalog/8727891aef3d4a57985d393ded635fe5?fx=net46)][5]).
* **Conflict resolution** – if both `launchProfileName` and `WithLaunchSettings` modify the same project, delegate wins; docs must state precedence clearly ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/launch-profiles)][1]).
* **Tooling parity** – Visual Studio templates still emit JSON; guidance must note that code overrides file values at runtime ([[learn.microsoft.com](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview?utm_source=chatgpt.com)][4]).
[1]: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/launch-profiles ".NET Aspire and launch profiles - .NET Aspire | Microsoft Learn"
[2]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.projectresourcebuilderextensions.addproject?view=dotnet-aspire-9.0 "ProjectResourceBuilderExtensions.AddProject Method (Aspire.Hosting) | Microsoft Learn"
[3]: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/app-host-overview?utm_source=chatgpt.com "NET Aspire orchestration overview - Learn Microsoft"
[4]: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/networking-overview?utm_source=chatgpt.com "NET Aspire inner loop networking overview - Learn Microsoft"
[5]: https://apisof.net/catalog/8727891aef3d4a57985d393ded635fe5?fx=net46 ".NET API Catalog"
[6]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withenvironment?view=dotnet-aspire-9.0 "ResourceBuilderExtensions.WithEnvironment Method (Aspire.Hosting) | Microsoft Learn"
[7]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withargs?view=dotnet-aspire-9.0 "ResourceBuilderExtensions.WithArgs Method (Aspire.Hosting) | Microsoft Learn"
[8]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.projectresourcebuilderextensions.withreplicas?view=dotnet-aspire-9.2&utm_source=chatgpt.com "ProjectResourceBuilderExtensions.WithReplicas Method (Aspire ..."
[9]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withendpoint?view=dotnet-aspire-9.0&utm_source=chatgpt.com "ResourceBuilderExtensions.WithEndpoint Method (Aspire.Hosting)"
[10]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.applicationmodel.projectresource?view=dotnet-aspire-8.0 "ProjectResource Class (Aspire.Hosting.ApplicationModel) | Microsoft Learn"
[11]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withendpoint?view=dotnet-aspire-9.0 "ResourceBuilderExtensions.WithEndpoint Method (Aspire.Hosting) | Microsoft Learn"
[12]: https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/launch-profiles ".NET Aspire and launch profiles - .NET Aspire | Microsoft Learn"
[13]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.resourcebuilderextensions.withenvironment?view=dotnet-aspire-9.0 "ResourceBuilderExtensions.WithEnvironment Method (Aspire.Hosting) | Microsoft Learn"
[14]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.applicationmodel.launchprofileannotation?view=dotnet-aspire-9.2&viewFallbackFrom=dotnet-aspire-8.0&utm_source=chatgpt.com "LaunchProfileAnnotation Class (Aspire.Hosting.ApplicationModel)"
[15]: https://learn.microsoft.com/en-us/dotnet/api/aspire.hosting.projectresourcebuilderextensions.withreplicas?view=dotnet-aspire-9.2&utm_source=chatgpt.com "ProjectResourceBuilderExtensions.WithReplicas Method (Aspire ..."
Contributor guide
Assessment
This issue has not been assessed yet.