aspire
aspire copied to clipboard
API Proposal: builder.When(predicate, callback)
Background and Motivation
When using the fluent-like API in the .NET Aspire app model developers sometimes find themselves wanting to conditionally apply a method to a resource builder. For example, you might want to only add a reference to a resource in publish mode, or for a particular environment.
Today to do this you need to break out of the fluent pattern to add conditional blocks to do this because C# doesn't have an inline conditional method invocation (as far as I know). Example of current approach:
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("pgsql").AddDatabase("db");
var myapp = builder.AddProject<Projects.MyApp>("myapp")
.WithReference(db);
if (builder.ExecutionContext.Operation = DistributedApplicationOperation.Publish)
{
var ai = builder.AddAzureApplicationInsights("ai");
myapp.WithReference(ai);
}
This makes the code look a lot less concise. Here is an example which inspired this API proposal:
https://github.com/dotnet/eShop/pull/464
Proposed API
namespace Aspire.Hosting;
public static class ResourceBuilderExtensions
{
+ public static IResourceBuilder<T> When<T>(
+ this IResourceBuilder<T> builder,
+ Func<bool> predicate,
+ Action<IResourceBuilder<T>> callback) where T: IResource
}
Usage Examples
Applying the example above to this new API design:
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("pgsql").AddDatabase("db");
var myapp = builder.AddProject<Projects.MyApp>("myapp")
.WithReference(db);
.When(builder.Execution.Operation == DistributedApplicationOperation.Publish, b => {
var ai = builder.AddAzureApplicationInsights("ai");
b.WithReference(ai);
});
To help make things even more concise we could add reusable conditional functions:
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("pgsql").AddDatabase("db");
var myapp = builder.AddProject<Projects.MyApp>("myapp")
.WithReference(db);
.When(builder.Execution.PublishCondition, b => {
var ai = builder.AddAzureApplicationInsights("ai");
b.WithReference(ai);
});
Alternative Designs
We could add conditional logic to methods like WithReference and WithEnvironment. However this would further complicate the set of overloads on these methods so this general purpose helper method is probably the most flexible building block that doesn't require additional ongoing work to implement.
Risks
One day we might get a more elaborate method invocation syntax for C# which makes this redundant.
@samsp-msft @mattmccleary @eerhardt @davidfowl @maddymontaquila @DamianEdwards
@rajkumar-rangaraj @TimothyMothra @vishweshbankwar, FYI, feedback welcome.
I’d love to see a more convincing example. Something that goes from ugly ifs to clean When calls.
Another example:
var nodeApp = builder.AddJavaScriptApp("node-joke-api", "../NodeApp", "start")
.WithPnpm()
If([System.OperatingSystem]::IsWindows(), builder => builder.WithEnvironment("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\AppData\Roaming\fnm\aliases\default")))
If(![System.OperatingSystem]::IsWindows(), builder => builder.WithEnvironment("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + "/tmp/directory/"))
.WithHttpEndpoint(env: "PORT")