From 49b25eaf7bf5960a40d06dedea00e53a5f13d9eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:25:03 +0000 Subject: [PATCH 1/6] Initial plan From 0dbc2b0385844c63b2da16050db60f63b4d9bf44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:42:11 +0000 Subject: [PATCH 2/6] Fix CommandLineArgsCallbackContext ExecutionContext in AzureResourcePreparer Set the ExecutionContext property when creating CommandLineArgsCallbackContext in AzureResourcePreparer.GetAzureReferences() to match how EnvironmentCallbackContext is created. This ensures callbacks receive the correct execution context (Publish vs Run mode), preventing WithVSCodeDebugSupport from incorrectly attempting to access ServiceProvider during manifest generation. Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com> --- .../AzureResourcePreparer.cs | 5 ++- .../AzureResourcePreparerTests.cs | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Hosting.Azure/AzureResourcePreparer.cs b/src/Aspire.Hosting.Azure/AzureResourcePreparer.cs index f2423151be8..4030996136b 100644 --- a/src/Aspire.Hosting.Azure/AzureResourcePreparer.cs +++ b/src/Aspire.Hosting.Azure/AzureResourcePreparer.cs @@ -380,7 +380,10 @@ private async Task> GetAzureReferences(IResource resourc if (resource.TryGetAnnotationsOfType(out var commandLineArgsCallbackAnnotations)) { - var context = new CommandLineArgsCallbackContext([], resource, cancellationToken: cancellationToken); + var context = new CommandLineArgsCallbackContext([], resource, cancellationToken: cancellationToken) + { + ExecutionContext = executionContext + }; foreach (var c in commandLineArgsCallbackAnnotations) { diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs index af04b88e227..95700d31ba8 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs @@ -235,6 +235,38 @@ public async Task NullCommandLineArgIsIgnored() Assert.True(true); } + [Fact] + public async Task CommandLineArgsCallbackContextHasCorrectExecutionContextDuringPublish() + { + using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); + builder.AddAzureContainerAppEnvironment("env"); + + // Create a project with a WithArgs callback that checks IsRunMode before accessing ServiceProvider + // This simulates what WithVSCodeDebugSupport does + var api = builder.AddProject("api", launchProfileName: null) + .WithArgs(context => + { + // This simulates WithVSCodeDebugSupport behavior - checking IsRunMode before accessing ServiceProvider + if (!context.ExecutionContext.IsRunMode) + { + return; + } + + // This should not be reached during publish mode, but if the ExecutionContext is not set correctly, + // it will default to Run mode and then try to access ServiceProvider which will throw + _ = context.ExecutionContext.ServiceProvider; + }); + + using var app = builder.Build(); + + // This should not throw because ExecutionContext should be set to Publish mode + // and the IsRunMode check should prevent accessing ServiceProvider + await ExecuteBeforeStartHooksAsync(app, default); + + // Test passes if we reach this point without exceptions + Assert.True(true); + } + private sealed class Project : IProjectMetadata { public string ProjectPath => "project"; From 0923b7d2061a34f95f1b932451a5555e45941394 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:08:09 +0000 Subject: [PATCH 3/6] Only execute WithVSCodeDebugSupport in run mode Add check at method level to only register WithArgs callback when builder.ApplicationBuilder.ExecutionContext.IsRunMode is true. This prevents the callback from being registered during publish mode, avoiding unnecessary callback evaluation during manifest generation. Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com> --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 129c5e0e5f4..8f03bd4f6e1 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -2310,15 +2310,10 @@ public static IResourceBuilder WithVSCodeDebugSupport(this IResourceBuilde ArgumentException.ThrowIfNullOrWhiteSpace(projectPath); ArgumentException.ThrowIfNullOrWhiteSpace(debugAdapterId); - if (builder is IResourceBuilder resourceWithArgs) + if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && builder is IResourceBuilder resourceWithArgs) { resourceWithArgs.WithArgs(ctx => { - if (!ctx.ExecutionContext.IsRunMode) - { - return; - } - var config = ctx.ExecutionContext.ServiceProvider.GetRequiredService(); if (ExtensionUtils.IsExtensionHost(config) && argsCallback is not null) { From a275fa87e9bd70f39864adf59c5de2c661eeff01 Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 1 Oct 2025 13:21:30 -0700 Subject: [PATCH 4/6] Update src/Aspire.Hosting/ResourceBuilderExtensions.cs --- src/Aspire.Hosting/ResourceBuilderExtensions.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 8f03bd4f6e1..911f09ee8e5 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -2310,7 +2310,12 @@ public static IResourceBuilder WithVSCodeDebugSupport(this IResourceBuilde ArgumentException.ThrowIfNullOrWhiteSpace(projectPath); ArgumentException.ThrowIfNullOrWhiteSpace(debugAdapterId); - if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && builder is IResourceBuilder resourceWithArgs) + if (!builder.ApplicationBuilder.ExecutionContext.IsRunMode) + { + return builder; + } + + if (builder is IResourceBuilder resourceWithArgs) { resourceWithArgs.WithArgs(ctx => { From ce428ebbf2435dd7db3d6aecb172055a3dad858c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:36:41 +0000 Subject: [PATCH 5/6] Add tests for WithVSCodeDebugSupport behavior in publish mode Added tests to verify that WithVSCodeDebugSupport does not add the SupportsDebuggingAnnotation in publish mode, only in run mode. This ensures the debugging annotation is only added when appropriate. Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com> --- .../ResourceBuilderExtensions.cs | 4 ++- ...ExecutableResourceBuilderExtensionTests.cs | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 911f09ee8e5..10c8314b5db 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -2327,7 +2327,9 @@ public static IResourceBuilder WithVSCodeDebugSupport(this IResourceBuilde }); } - return builder.WithAnnotation(new SupportsDebuggingAnnotation(projectPath, debugAdapterId, requiredExtensionId)); + builder.WithAnnotation(new SupportsDebuggingAnnotation(projectPath, debugAdapterId, requiredExtensionId)); + + return builder; } /// diff --git a/tests/Aspire.Hosting.Tests/ExecutableResourceBuilderExtensionTests.cs b/tests/Aspire.Hosting.Tests/ExecutableResourceBuilderExtensionTests.cs index 2d8818f1277..db6a2f60bb6 100644 --- a/tests/Aspire.Hosting.Tests/ExecutableResourceBuilderExtensionTests.cs +++ b/tests/Aspire.Hosting.Tests/ExecutableResourceBuilderExtensionTests.cs @@ -1,5 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. + +#pragma warning disable ASPIREEXTENSION001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. +#pragma warning disable IDE0005 // Using directive is unnecessary. + +using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; namespace Aspire.Hosting.Tests; @@ -65,4 +70,29 @@ public void WithWorkingDirectoryAllowsEmptyString() var annotation = executable.Resource.Annotations.OfType().Single(); Assert.Equal(builder.AppHostDirectory, annotation.WorkingDirectory); } + + [Fact] + public void WithVSCodeDebugSupportAddsAnnotationInRunMode() + { + using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Run); + var executable = builder.AddExecutable("myexe", "command", "workingdirectory") + .WithVSCodeDebugSupport("project.py", "python", "ms-python.python"); + + var annotation = executable.Resource.Annotations.OfType().SingleOrDefault(); + Assert.NotNull(annotation); + Assert.Equal("project.py", annotation.ProjectPath); + Assert.Equal("python", annotation.DebugAdapterId); + Assert.Equal("ms-python.python", annotation.RequiredExtensionId); + } + + [Fact] + public void WithVSCodeDebugSupportDoesNotAddAnnotationInPublishMode() + { + using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); + var executable = builder.AddExecutable("myexe", "command", "workingdirectory") + .WithVSCodeDebugSupport("project.py", "python", "ms-python.python"); + + var annotation = executable.Resource.Annotations.OfType().SingleOrDefault(); + Assert.Null(annotation); + } } \ No newline at end of file From 0301ba3fdcd98d195bf50988905b653d576f10e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:39:48 +0000 Subject: [PATCH 6/6] Address PR feedback: revert formatting and improve test - Reverted formatting change in ResourceBuilderExtensions.cs (return statement on one line) - Improved CommandLineArgsCallbackContextHasCorrectExecutionContextDuringPublish test to: - Remove unnecessary IsRunMode check in callback - Capture ExecutionContext to verify it's set correctly - Assert ExecutionContext is not null and in Publish mode Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com> --- .../ResourceBuilderExtensions.cs | 4 +-- .../AzureResourcePreparerTests.cs | 25 ++++++++----------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/Aspire.Hosting/ResourceBuilderExtensions.cs b/src/Aspire.Hosting/ResourceBuilderExtensions.cs index 10c8314b5db..911f09ee8e5 100644 --- a/src/Aspire.Hosting/ResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting/ResourceBuilderExtensions.cs @@ -2327,9 +2327,7 @@ public static IResourceBuilder WithVSCodeDebugSupport(this IResourceBuilde }); } - builder.WithAnnotation(new SupportsDebuggingAnnotation(projectPath, debugAdapterId, requiredExtensionId)); - - return builder; + return builder.WithAnnotation(new SupportsDebuggingAnnotation(projectPath, debugAdapterId, requiredExtensionId)); } /// diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs index 95700d31ba8..96af844a4c7 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs @@ -241,30 +241,25 @@ public async Task CommandLineArgsCallbackContextHasCorrectExecutionContextDuring using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); builder.AddAzureContainerAppEnvironment("env"); - // Create a project with a WithArgs callback that checks IsRunMode before accessing ServiceProvider - // This simulates what WithVSCodeDebugSupport does + DistributedApplicationExecutionContext? capturedExecutionContext = null; + + // Create a project with a WithArgs callback that captures the ExecutionContext var api = builder.AddProject("api", launchProfileName: null) .WithArgs(context => { - // This simulates WithVSCodeDebugSupport behavior - checking IsRunMode before accessing ServiceProvider - if (!context.ExecutionContext.IsRunMode) - { - return; - } - - // This should not be reached during publish mode, but if the ExecutionContext is not set correctly, - // it will default to Run mode and then try to access ServiceProvider which will throw - _ = context.ExecutionContext.ServiceProvider; + // Capture the ExecutionContext to verify it's set correctly + capturedExecutionContext = context.ExecutionContext; }); using var app = builder.Build(); - // This should not throw because ExecutionContext should be set to Publish mode - // and the IsRunMode check should prevent accessing ServiceProvider + // This should not throw - the ExecutionContext should be set correctly await ExecuteBeforeStartHooksAsync(app, default); - // Test passes if we reach this point without exceptions - Assert.True(true); + // Verify the ExecutionContext was captured and is in Publish mode + Assert.NotNull(capturedExecutionContext); + Assert.True(capturedExecutionContext.IsPublishMode); + Assert.False(capturedExecutionContext.IsRunMode); } private sealed class Project : IProjectMetadata