diff --git a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs index 4b3649423..fb4e77cad 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs @@ -210,7 +210,7 @@ private async Task OnBeforeStartAsync(BeforeStartEvent @event, CancellationToken ModelNamedArg("--unix-domain-socket", sidecarOptions?.UnixDomainSocket), PostOptionsArgs(Args(sidecarOptions?.Command))); - var daprCliResourceName = $"{daprSidecar.Name}-cli"; + var daprCliResourceName = sidecarOptions?.SidecarName ?? $"{daprSidecar.Name}-cli"; var daprCli = new ExecutableResource(daprCliResourceName, fileName, appHostDirectory); // Propagate WaitAnnotations from the original resource to the Dapr CLI executable diff --git a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprPolyglotOptions.cs b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprPolyglotOptions.cs index a759a1c50..cbec0a999 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprPolyglotOptions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprPolyglotOptions.cs @@ -56,6 +56,7 @@ internal sealed record DaprSidecarExportOptions public string? RuntimePath { get; init; } public string? SchedulerHostAddress { get; init; } public string? UnixDomainSocket { get; init; } + public string? SidecarName { get; init; } public DaprSidecarOptions ToDaprSidecarOptions() { @@ -93,7 +94,8 @@ public DaprSidecarOptions ToDaprSidecarOptions() RunFile = RunFile, RuntimePath = RuntimePath, SchedulerHostAddress = SchedulerHostAddress, - UnixDomainSocket = UnixDomainSocket + UnixDomainSocket = UnixDomainSocket, + SidecarName = SidecarName, }; #pragma warning restore CS0618 } diff --git a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprSidecarOptions.cs b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprSidecarOptions.cs index 3ef4bca3d..5be387048 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprSidecarOptions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Dapr/DaprSidecarOptions.cs @@ -241,4 +241,13 @@ public string? DaprReadBufferSize /// If specified, the Dapr sidecar will use Unix Domain Sockets for API calls. /// public string? UnixDomainSocket { get; init; } + + + /// + /// Gets or sets the name of the Dapr sidecar. + /// + /// + /// If specified, the Dapr sidecar name will be used. + /// + public string? SidecarName { get; init; } } diff --git a/src/CommunityToolkit.Aspire.Hosting.Dapr/IDistributedApplicationComponentBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.Dapr/IDistributedApplicationComponentBuilderExtensions.cs index 423775c63..c0fd169d0 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Dapr/IDistributedApplicationComponentBuilderExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Dapr/IDistributedApplicationComponentBuilderExtensions.cs @@ -36,7 +36,12 @@ public static IResourceBuilder WithDaprSidecar(this IResourceBuilder bu [AspireExportIgnore(Reason = "Use the exported DTO-based overload instead to avoid ambiguous polyglot wrapper generation.")] public static IResourceBuilder WithDaprSidecar(this IResourceBuilder builder, DaprSidecarOptions? options = null) where T : IResource { - return builder.WithDaprSidecar( + var sidecarName = string.IsNullOrWhiteSpace(options?.SidecarName) + ? $"{builder.Resource.Name}-dapr" + : options.SidecarName; + + return builder.WithDaprSidecarCore( + sidecarName, sidecarBuilder => { if (options is not null) @@ -61,11 +66,37 @@ internal static IResourceBuilder WithDaprSidecarExport(this IResourceBuild /// The resource builder instance. [AspireExport("configureDaprSidecar", MethodName = "configureDaprSidecar", Description = "Adds a Dapr sidecar to the resource and exposes it for callback configuration")] public static IResourceBuilder WithDaprSidecar(this IResourceBuilder builder, Action> configureSidecar) where T : IResource + { + return builder.WithDaprSidecarCore($"{builder.Resource.Name}-dapr", configureSidecar); + } + + /// + /// Ensures that a Dapr sidecar is started for the resource with a custom sidecar name. + /// + /// The type of the resource. + /// The resource builder instance. + /// The Aspire resource name for the Dapr sidecar. + /// A callback that can be use to configure the Dapr sidecar. + /// The resource builder instance. + public static IResourceBuilder WithDaprSidecar( + this IResourceBuilder builder, + string sidecarName, + Action> configureSidecar) where T : IResource + { + return builder.WithDaprSidecarCore( + string.IsNullOrWhiteSpace(sidecarName) ? $"{builder.Resource.Name}-dapr" : sidecarName, + configureSidecar); + } + + private static IResourceBuilder WithDaprSidecarCore( + this IResourceBuilder builder, + string sidecarName, + Action> configureSidecar) where T : IResource { // Add Dapr is idempotent, so we can call it multiple times. builder.ApplicationBuilder.AddDapr(); - var sidecarBuilder = builder.ApplicationBuilder.AddResource(new DaprSidecarResource($"{builder.Resource.Name}-dapr")) + var sidecarBuilder = builder.ApplicationBuilder.AddResource(new DaprSidecarResource(sidecarName)) .WithInitialState(new() { Properties = [], diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/DaprTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/DaprTests.cs index df7fd990d..fcfc34026 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/DaprTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/DaprTests.cs @@ -4,6 +4,7 @@ using Aspire.Hosting; using Aspire.Hosting.Utils; using CommunityToolkit.Aspire.Testing; +using Microsoft.AspNetCore.Http; namespace CommunityToolkit.Aspire.Hosting.Dapr.Tests; @@ -165,4 +166,24 @@ public async Task WithDaprSideCarAddsAnnotationBasedOnTheSidecarAppOptions(strin Assert.Contains($"--app-protocol {expectedSchema}", commandline); Assert.NotNull(container.Annotations.OfType()); } + + [Theory] + [InlineData("MyName", "MyName")] + [InlineData(null, "name-dapr")] + public void WithDaprSidecarName(string? sidecarName, string expectedSidecarName) + { + using var builder = TestDistributedApplicationBuilder.Create(); + + var containerResource = builder.AddContainer("name", "image"); + + containerResource.WithDaprSidecar(new DaprSidecarOptions + { + SidecarName = sidecarName + }); + + var annotation = Assert.Single( + containerResource.Resource.Annotations.OfType()); + + Assert.Equal(expectedSidecarName, annotation.Sidecar.Name); + } }