Add better WithDebugSupport extensibility api#12711
Add better WithDebugSupport extensibility api#12711adamint wants to merge 81 commits intodotnet:mainfrom
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12711Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12711" |
…ble-debug-support
src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the debugging support infrastructure for Aspire resources by introducing a more structured approach to configuring debugger properties. The main purpose is to enable customizable debugging experiences for Python and other resources by allowing developers to configure debugger-specific properties (like stop-on-entry, auto-reload, etc.) through a strongly-typed API.
Key changes:
- Introduces
DebuggerPropertiesbase class andExecutableLaunchConfigurationWithDebuggerProperties<T>for type-safe debugger configuration - Adds new
WithDebuggerPropertiesandWithPythonDebuggerPropertiesextension methods for configuring debug settings - Refactors launch configuration producer to pass
LaunchConfigurationProducerOptionsinstead of just a string mode - Moves shared debug support logic from multiple locations into
ResourceDebugSupportExtensions.cs
Reviewed Changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Aspire.Hosting/ExecutableLaunchConfiguration.cs | New file defining base classes for launch configurations with debugger properties support |
| src/Aspire.Hosting/ExecutableDebuggerPropertiesAnnotation.cs | New annotation for attaching debugger configuration to resources |
| src/Aspire.Hosting/SupportsDebuggingAnnotation.cs | Changed visibility to public, updated to use LaunchConfigurationProducerOptions |
| src/Aspire.Hosting/ResourceBuilderExtensions.cs | Moved WithDebugSupport and added new WithDebuggerProperties extension method |
| src/Aspire.Hosting.Python/PythonAppLaunchConfiguration.cs | Extended to include full Python debugger properties and configuration options |
| src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs | Updated to use new debugger properties infrastructure and added WithPythonDebuggerProperties |
| src/Shared/ResourceDebugSupportExtensions.cs | New shared file consolidating debug support logic previously scattered across files |
| src/Aspire.Hosting/Dcp/DcpExecutor.cs | Updated to inject and use IBackchannelLoggerProvider for debug console logging |
| src/Aspire.Hosting/Backchannel/BackchannelLoggerProvider.cs | Added IBackchannelLoggerProvider interface for testability |
| tests/* | Updated tests to use CustomExecutableLaunchConfiguration and new API signatures |
| extension/* | TypeScript changes to support debugger_properties in launch configurations |
src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
extension/src/utils/workspace.ts
Outdated
| cliAvailableOnPath = true; | ||
| return true; | ||
| } catch (error) { | ||
| extensionLogOutputChannel.error(`Aspire CLI not found at path: ${cliPath}. Error: ${error}`); |
|
|
||
| // General 404 handler (for non-API routes) | ||
| app.use('*', (req, res) => { | ||
| app.use((req, res) => { |
There was a problem hiding this comment.
the framework changed and this is required
| /// be extended to map to the properties made available by any VS Code debug adapter. | ||
| /// </summary> | ||
| [Experimental("ASPIREEXTENSION001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] | ||
| public abstract class VSCodeDebuggerProperties |
There was a problem hiding this comment.
Consider DebugAdapterProperties as a more IDE agnostic name.
| public abstract class VSCodeDebuggerProperties | |
| public abstract class DebugAdapterProperties |
There was a problem hiding this comment.
Actually, thinking about this a bit more; I think it makes sense to make the VSCode specific properties a separate (or child) section of the debug properties. This type is currently effectively the standard debug adapter protocol launch/attach configuration with VSCode specific types mixed in. We can extend this pattern to support VS (and other) editors if we treat the IDE specific config as a distinct payload.
There was a problem hiding this comment.
The actual DAP specific configuration is effectively determined by the type, request, and (for launch requests) the noDebug property. Everything else is VSCode specific.
There was a problem hiding this comment.
Effectively that'd mean splitting out the "how do I debug this thing" DAP specific properties from the VSCode specific config.
| /// The label of a task to launch before the start of a debug session. Can be set to ${defaultBuildTask} to use the default build task. | ||
| /// </summary> | ||
| [JsonPropertyName("preLaunchTask")] | ||
| public string? PreLaunchTask { get; set; } |
There was a problem hiding this comment.
Philosophically, I wonder if we need something to solve what vscode pre-launch and post-launch tasks solve directly in Aspire. Ideally Aspire itself would know everything required to build the project for debug.
There was a problem hiding this comment.
I don't think so. Pre-launch tasks are already supported in the existing application model using resource dependencies, and post-launch tasks are supported using WaitFor
There was a problem hiding this comment.
ie, the existing JS hosting extension has a pre-launch 'build' task
There was a problem hiding this comment.
I prefer the idea of steering users towards using idiomatic Aspire patterns if possible, but I can understand that there are users who will want to do things the VSCode way if they needed to convert an existing app to use Aspire, so I think these do probably make sense to include.
| /// Controls how the debug configuration is displayed in the UI. | ||
| /// </summary> | ||
| [JsonPropertyName("presentation")] | ||
| public PresentationOptions? Presentation { get; set; } |
There was a problem hiding this comment.
Is the idea that we would have an Aspire specific sidebar to display service debugging sessions? I'd want to avoid surfacing service specific launch targets in the main VSCode debug launch UI to avoid confusion with the core Aspire launch target.
There was a problem hiding this comment.
@maddymontaquila and I were just talking about showing running apphosts in UI. I think it's a good idea, and this property could be used to control ordering visually. However, presentation is a property supported by VS Code launch configurations (https://code.visualstudio.com/docs/debugtest/debugging-configuration), so I included it here
There was a problem hiding this comment.
I'd argue for omitting any properties we don't HAVE to support for services, just to minimize the initial footprint. Better to add them progressively once we have a reason to support them.
| /// Possible values: "neverOpen", "openOnSessionStart", "openOnFirstSessionStart". | ||
| /// </summary> | ||
| [JsonPropertyName("internalConsoleOptions")] | ||
| public string? InternalConsoleOptions { get; set; } |
There was a problem hiding this comment.
I think it makes sense to include this for now, but in the future once DCP implements a DAP client, I expect this'll eventually be overridden to allow DCP to drive and forward PTTY sessions for debugged services to the dashboard.
| /// Allows you to connect to a specified port instead of launching the debug adapter. | ||
| /// </summary> | ||
| [JsonPropertyName("debugServer")] | ||
| public int? DebugServer { get; set; } |
There was a problem hiding this comment.
This is effectively debug adapter config and isn't unique to VSCode, particularly once we introduce our own debug adapter protocol implementation. Either the extension or the app model will need to know how to actually start the individual debug adapters and whether they communicate over stdio, TCP, etc.
…, fix browser UserDataDir to use boolean true for auto-temp-dir
…ble-debug-support
| "description": "Enable or disable the 'aspire exec' command for executing commands inside running resources", | ||
| "default": false | ||
| }, | ||
| "experimentalPolyglot:go": { |
… to release/13.2) Reworks the debug support API so it's not tied to VS Code. Lets any IDE plug in their own debug configuration by extending a common base. Key changes: - New class hierarchy: DebugAdapterProperties -> VSCodeDebuggerPropertiesBase -> concrete classes - IDE detection via AspireIde class and ASPIRE_IDE env var - Filtered annotations with optional ideType parameter - Polymorphic JSON serialization for derived types - VS Code extension simplified to spread debugger_properties directly
| _innerBuilder.Services.AddSingleton(TimeProvider.System); | ||
|
|
||
| _innerBuilder.Services.AddSingleton<ILoggerProvider, BackchannelLoggerProvider>(); | ||
| _innerBuilder.Services.AddSingleton<IBackchannelLoggerProvider, BackchannelLoggerProvider>(); |
There was a problem hiding this comment.
Is this technically a breaking change? I thought logger infrastructure resolves IEnumerable to find log providers, so does this mean this one will now get missed? I would have expected something like:
_innerBuilder.Services.AddSingleton<BackchannelLoggerProvider>();
_innerBuilder.Services.AddSingleton<ILoggerProvider>(sp => sp.GetRequiredService<BackchannelLoggerProvider>());
_innerBuilder.Services.AddSingleton<IBackchannelLoggerProvider>(sp => sp.GetRequiredService<BackchannelLoggerProvider>());|
|
||
| if (!configuration) { | ||
| extensionLogOutputChannel.error(`Failed to create debug configuration for ${JSON.stringify(launchConfig)} - resulting configuration was undefined or empty.`); | ||
| throw new Error(invalidLaunchConfiguration(JSON.stringify(configuration))); |
There was a problem hiding this comment.
should this be launchConfig instead of configuration?
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add better WithDebugSupport extensibility API (backport of #12711 to release/13.2) Reworks the debug support API so it's not tied to VS Code. Lets any IDE plug in their own debug configuration by extending a common base. Key changes: - New class hierarchy: DebugAdapterProperties -> VSCodeDebuggerPropertiesBase -> concrete classes - IDE detection via AspireIde class and ASPIRE_IDE env var - Filtered annotations with optional ideType parameter - Polymorphic JSON serialization for derived types - VS Code extension simplified to spread debugger_properties directly * Fix BackchannelLoggerProvider DI registration and clear launch configs on restart - Register BackchannelLoggerProvider as both ILoggerProvider and IBackchannelLoggerProvider so the logging pipeline can discover it. - Clear launch configurations annotation before re-annotating in CreateExecutableAsync to prevent stale configs (with null debugger_properties due to abstract deserialization) from accumulating on resource restart. * Make WithVSCodeDebugging internal, add public WithDebugging/WithBrowserDebugger - Made WithVSCodeDebugging internal across all packages (Hosting, JavaScript, Python) - Added public WithDebugging methods that delegate to internal WithVSCodeDebugging: - WithDebugging<T>(builder, projectPath) for ProjectResource - WithDebugging<T>(builder, scriptPath) for NodeAppResource - WithDebugging<T>(builder) for JavaScriptAppResource - WithDebugging<T>(builder) for PythonAppResource - WithBrowserDebugger<T>(builder, browser) remains public for JavaScriptAppResource - Python WithDebugging is no longer [Obsolete], now marked [Experimental] - All underlying types/infrastructure remain internal - Removed playground calls to now-internal methods * Make WithVSCodeCSharpDebuggerProperties, WithVSCodeNodeDebuggerProperties, WithVSCodePythonDebuggerProperties internal; split WithBrowserDebugger into public (no config) + internal (with config) * Fix JavaScript hosting: make WithVSCodeNodeDebuggerProperties internal, split WithBrowserDebugger into public/internal overloads * Make all debug infrastructure types internal, fix csproj IVT entries and shared file includes * Simplify debug infrastructure and add tests - Fix Path.GetDirectoryName null-bypass with safe fallback - Move JS debugger property defaults (SkipFiles, SourceMaps, AutoAttachChildProcesses) to field initializers - Fix empty Python interpreter path: fallback to 'python' with warning - Add 11 new tests across Hosting, JavaScript, and Python debug tests
Description
This PR adds extensible debug support APIs to Aspire, allowing any IDE to plug in their own debug configuration by extending a common base. The debug infrastructure types are kept internal while exposing a minimal, IDE-agnostic public API surface.
Public API Surface (all marked
[Experimental("ASPIREEXTENSION001")])Aspire.Hosting:
WithDebugging<T>(builder, string projectPath)whereT : ProjectResource— Configures debugging for project resources (only needed for customProjectResourceinheritors)Aspire.Hosting.JavaScript:
WithDebugging<T>(builder, string scriptPath)whereT : NodeAppResource— Configures debugging for Node.js apps with a script pathWithDebugging<T>(builder)whereT : JavaScriptAppResource— Configures debugging for JavaScript apps using package manager scriptsWithBrowserDebugger<T>(builder, string browser = "msedge")whereT : JavaScriptAppResource— Configures browser debugging by creating a child browser debugger resourceAspire.Hosting.Python:
WithDebugging<T>(builder)whereT : PythonAppResource— Configures debugging for Python appsInternal Infrastructure
All debug property classes, launch configuration types, and infrastructure methods are internal:
WithVSCodeDebugging(all packages) — now internal, delegated to by publicWithDebuggingWithDebugSupport,WithDebuggerProperties,WithVSCodeDebugOptionsWithVSCode*DebuggerPropertiesmethodsExecutableLaunchConfiguration,DebugAdapterProperties,VSCodeDebuggerPropertiesBase,SupportsDebuggingAnnotation,LaunchConfigurationProducerOptions,ProjectLaunchConfiguration,NodeLaunchConfiguration,BrowserLaunchConfiguration, etc.Cross-assembly access is enabled via
InternalsVisibleTo.Key Design Concepts
DebugAdapterProperties— abstract base for DAP-standard properties any IDE can useVSCodeDebuggerPropertiesBase— adds VS Code-specific options (presentation,preLaunchTask,serverReadyAction)AspireIdeclass andExecutableDebuggerPropertiesAnnotation— annotations only fire when the matching IDE is runningDebugAdapterPropertiesJsonConverterfor derived type serializationWithDebugging/WithBrowserDebugger(notWithVSCodeDebugging) so the API is stable across IDE implementationsSummary of Changes
WithVSCodeDebugging)WithDebuggingmethods across all packages that delegate to internalWithVSCodeDebuggingWithBrowserDebuggerfor JavaScript resourcesWithDebuggingis no longer[Obsolete]— it is now the canonical public APIInternalsVisibleTofor cross-assembly access between hosting packagesLaunchConfigurationAnnotatorcall inDcpExecutor.PreparePlainExecutablesChecklist
<remarks>and<code/>elements on your triple slash comments?