Add VS Code attach debugger resource action - #18602
Add VS Code attach debugger resource action#18602Adam Ratzman (adamint) wants to merge 16 commits into
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18602Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18602" |
There was a problem hiding this comment.
Pull request overview
This PR adds the first VS Code extension lane for #18538: a right-click Attach debugger action on running .NET project resources in the Aspire panel. It builds a CoreCLR attach debug configuration that targets the project's process by processName (best-effort resolving <AssemblyName> from the project file), rather than executable.pid, because DCP reports the dotnet run launcher PID rather than the child app process. The action is gated on a running top-level Project resource with a dotnet executable and a .csproj/.fsproj/.vbproj path, and only when the C# extension is installed; it re-resolves the latest resource before attaching so stale/ambiguous/missing resources fail closed with a warning.
Bundled alongside the feature is a broad telemetry overhaul: every event is renamed to its final wire name (aspire/vscode/... and aspire/dashboard/...) and routed through sendDangerousTelemetryEvent/sendDangerousTelemetryErrorEvent to bypass VS Code's automatic <extensionId>/ prefix, with manual opt-in gating (telemetryLevel), manual common properties, and explicit value sanitization.
Changes:
- Add
aspire-vscode.attachDebuggerToResourcecommand, menu contribution (canAttachDebuggercontext value), attachability helpers, and the attach execution flow with latest-resource re-resolution. - Rename all telemetry events to final wire names and route them through the "dangerous" send path with explicit gating/sanitization and manually-added common properties.
- Add localized strings and extensive unit tests for both the attach flow and the telemetry changes.
Show a summary per file
| File | Description |
|---|---|
extension/src/views/AspireAppHostTreeProvider.ts |
Core attach logic: attachability helpers, process-name derivation, attachDebuggerToResource, latest-resource resolution; propagates appHostPath through tree items. |
extension/src/extension.ts |
Registers the new attach command; renames the extension/activated telemetry event. |
extension/package.json |
Contributes the command, hidden palette entry, and view/item/context menu item; reorders action groups. |
extension/package.nls.json / extension/src/loc/strings.ts / extension/loc/xlf/aspire-vscode.xlf |
Adds/regenerates localized strings for the attach action. |
extension/src/utils/telemetry.ts |
Switches to dangerous-send path, adds manual gating, common properties, and value sanitization; hard-codes telemetry client version. |
extension/src/utils/telemetryRegistry.ts |
Renames event schema keys to final aspire/vscode/... and aspire/dashboard/... wire names; documents the convention. |
extension/telemetry.json |
Updates classification inventory keys to the new wire names. |
extension/src/dcp/DashboardTelemetryPassthrough.ts / AspireDcpServer.ts / AspireDebugSession.ts / AppHostLaunchService.ts / AppHostsViewTelemetry.ts / meaningfulEngagement.ts / appHostDiscovery.ts / workspace.ts / interactionService.ts |
Update event-name call sites and passthrough comments to the new namespaces. |
extension/src/test/*.test.ts, extension/src/test-e2e/packageSurface.e2e.test.ts |
Extensive tests for the attach flow, telemetry gating/sanitization/naming, and the manifest/surface contributions. |
Review details
- Files reviewed: 29/29 changed files
- Comments generated: 3
- Review effort level: Medium
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
I tried to place these as inline tracking comments, but GitHub rejected new inline comments because there is already a pending review draft for this user on the PR. I kept the tracking here instead while the branch was fixed:
These were fixed before the later Windows punctuation redaction follow-up. This is a top-level tracking comment, so there is no review thread to resolve; final tracking is in #18602 (comment). |
|
Pushed Validation on the live head passed locally: Remaining non-agent gates: live CoreCLR attach/manual readiness pass, plus telemetry/reviewer sign-off for the |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Avoid the broken azure-functions-core-tools@4 latest package, which currently downloads missing native CLI zip assets and fails Playground/Azure CI setup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (2)
src/Aspire.Hosting/IProjectMetadata.cs:50
- The PR description says this consumes #19136's
project.assemblyName, but #19136 is closed without merging and this diff instead introduces a different public/build contract (IProjectMetadata.TargetName,project.targetName, and the SDK probe). The current description therefore hides that this PR now owns the contract and documents a property that will never be emitted. Update the description and validation/API-review scope to describe theTargetNamecontract, or rebase this contract onto a dependency that actually lands.
public string? TargetName => null;
extension/CHANGELOG.md:13
- This release-note entry points to #18602, but the telemetry wire-name work was split out and merged in #18562; #18602 is now the attach-debugger PR. Link the telemetry PR so readers reach the change that actually implemented this fix.
- Emit VS Code extension and dashboard telemetry with the `aspire/vscode/*` and `aspire/dashboard/*` wire names expected by downstream Aspire telemetry queries ([#18602](https://github.com/microsoft/aspire/pull/18602)).
- Files reviewed: 41/42 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Restores .github/workflows/run-tests.yml to main for this PR, reverting the out-of-scope 0ecf63b workflow change. The Azure Functions Core Tools fix now lives on adamint/fix-azfunc-core-tools-ci. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (5)
extension/src/views/resourceLookup.ts:67
- This helper only matches the PID even though global resource items now carry
appHostPath. After an AppHost restarts at the same path,findLatestResourceForElementcan resolve the replacement snapshot, but logs and resource commands still fail because this helper cannot resolve the new PID; if that PID was reused by a different AppHost, those operations can target the wrong path. Match by path first and use the sole path match as the restart fallback, as the latest-resource lookup already does.
export function findAppHostForResource(repository: AppHostDataRepository, element: ResourceElementRef): AppHostDisplayInfo | undefined {
return element.appHostPid !== null
? repository.appHosts.find(appHost => appHost.appHostPid === element.appHostPid)
: undefined;
extension/src/debugger/languages/dotnet.ts:46
- The stated dependency contract exposes
IProjectMetadata.AssemblyName/project.assemblyName, but this branch publishes and readsTargetName/project.targetName; #19136 is also currently closed without merging. As written, this does not consume #19136's contract as the PR description claims. Align the property contract across the hosting and extension changes, or update the dependency and PR description if this branch intentionally replaces #19136 with a target-name contract.
// Well-known snapshot property added by the AppHost SDK target-name contract.
// It carries the MSBuild-evaluated `TargetName`, which is the process name the C# debugger attaches to.
const projectTargetNamePropertyName = 'project.targetName';
tests/Aspire.Hosting.Sdk.Tests/AppHostSdkTargetsTests.cs:452
- Setting
BuildingProject=truedoes not test that probe failures are fatal because this referenced project succeeds. This test still passes if bothContinueOnErrorvalues are changed to tolerate errors, so the real-build failure policy remains uncovered. Add a case whoseGetTargetFrameworksorGetTargetPathtarget emits an error and assert the MSBuild invocation exits nonzero.
src/Aspire.Cli/Projects/DotNetBasedAppHostServerProject.cs:155 - This setting cannot affect the generated server project: after importing these SDK targets,
CreateProjectFilereplaces_CSharpWriteProjectMetadataSourceswith an empty target at lines 259-261, so its_SetAspireProjectMetadataTargetNamesdependency—and therefore the probe—is never run. Remove this dead property and its failure/cost rationale.
<!-- The ProjectReferences below are Aspire.Hosting.* libraries, not app resources anyone
attaches a debugger to, so probing each one for an evaluated TargetName is pure cost.
Skipping also keeps this real build from failing on a reference the probe cannot
evaluate, the same reasoning as SkipValidateAspireHostProjectResources above. -->
<SkipAspireProjectResourceTargetName>true</SkipAspireProjectResourceTargetName>
extension/CHANGELOG.md:13
- This telemetry fix was implemented and merged in #18562, not this attach-debugger PR. Keeping #18602 here misattributes the release note and makes this PR appear to contain telemetry behavior it no longer changes. Link the merged telemetry PR instead.
- Emit VS Code extension and dashboard telemetry with the `aspire/vscode/*` and `aspire/dashboard/*` wire names expected by downstream Aspire telemetry queries ([#18602](https://github.com/microsoft/aspire/pull/18602)).
- Files reviewed: 40/41 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (3)
src/Shared/Model/KnownProperties.cs:64
- #19136 is now closed without merging, so this branch is no longer merely consuming that dependency. It introduces the differently named
TargetName/project.targetNamecontract itself, while the PR body repeatedly saysAssemblyName/project.assemblyName. Update the description to disclose that this PR now owns the hosting/MSBuild contract and document the actual wire/API names, or restore a merged dependency matching the stated contract.
tests/Aspire.Hosting.Sdk.Tests/AppHostSdkTargetsTests.cs:462 - This test never causes either MSBuild probe to fail, so it passes whether
ContinueOnErroris strict or tolerant and does not cover the fatal behavior claimed by its name/comment. Add a worker hook that makesGetTargetFrameworksorGetTargetPathfail, then assert a nonzero result withBuildingProject=true(and tolerant behavior with it false if that is part of the contract).
extension/CHANGELOG.md:13 - This telemetry change was delivered by #18562, which is already merged; linking it to this attach-debugger PR misattributes the changelog entry.
- Emit VS Code extension and dashboard telemetry with the `aspire/vscode/*` and `aspire/dashboard/*` wire names expected by downstream Aspire telemetry queries ([#18602](https://github.com/microsoft/aspire/pull/18602)).
- Files reviewed: 40/41 changed files
- Comments generated: 1
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (4)
src/Aspire.Hosting/IProjectMetadata.cs:42
TargetNameis documented as the actual MSBuild property, but the generator assignsTargetPath's%(Filename)metadata, which removes the final extension. A third-party implementation following this contract could returnWorker.dll; the extension trusts any nonblank value directly as the CoreCLRprocessNameand would search forWorker.dllinstead ofWorker. Define this API explicitly as the extensionless debugger process name (and name/document it accordingly), or carry the realTargetNameand normalize it in the consumer.
/// This value is baked into the generated project metadata when the AppHost is built. It is the MSBuild-evaluated
/// <c>TargetName</c>, which defaults to <c>AssemblyName</c>, rather than the project file name. That distinction
/// matters when a project sets <c>TargetName</c> because the launched assembly is then named after the target
/// instead of the assembly or project file.
tests/Aspire.Hosting.Sdk.Tests/AppHostSdkTargetsTests.cs:452
- This does not exercise the claimed fatal-failure path: the probe succeeds, so changing
ContinueOnErrorto always ignore failures would leave the test green. Make the referenced project failGetTargetFrameworksorGetTargetPathand assert that this invocation exits nonzero whenBuildingProject=true(and optionally remains tolerant for the design-time case).
src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets:203 - All new target-name tests create only one referenced project, so they cannot catch cross-item metadata bleed in this path. Because this target batches one output list and correlates it with a separate metadata-source list by project path, add a case with at least two references having distinct target names and assert that each generated metadata file receives its own value.
<AspireProjectMetadataSource Update="@(AspireProjectMetadataSource)"
Condition="'$(_AspireResolvedTargetName)' != '' and '%(AspireProjectMetadataSource.ProjectPath)' == '$(_AspireResolvedProjectFile)'">
<ProjectTargetName>$(_AspireResolvedTargetName)</ProjectTargetName>
<ProjectTargetNameLiteral>$(_AspireResolvedTargetNameLiteral)</ProjectTargetNameLiteral>
src/Shared/Model/KnownProperties.cs:64
- The PR description and linked #19136 specify the compatibility contract as
project.assemblyName, but this change publishesproject.targetNameinstead. As written, an extension built against the described #19136 contract would not consume that property and would always take the fallback. Align the documented dependency and property contract with the implementation (or restore the assembly-name key) before merging the stacked changes.
- Files reviewed: 40/41 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Review details
Files not reviewed (1)
- src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (3)
tests/Aspire.Hosting.Sdk.Tests/AppHostSdkTargetsTests.cs:449
- This test never makes either MSBuild probe fail, so it does not verify the fatal behavior described by its name and comment. Changing both
ContinueOnErrorvalues to always continue would still pass. Please make the referenced project failGetTargetFrameworksorGetTargetPathwithBuildingProject=trueand assert that the MSBuild invocation fails; optionally also cover the tolerant design-time path.
src/Aspire.Hosting/IProjectMetadata.cs:47 - This states that third-party implementations return
null, butTargetNameis an overridable default interface member andResourceSnapshotBuilderpublishes any nonblank implementation value. Clarify thatnullis the default for implementations that cannot determine the name, rather than a requirement for all non-generated implementations.
/// Implementations that are not produced by the AppHost build - for example metadata created from a project
/// path at runtime, file-based apps, or third-party implementations - return <see langword="null"/>. Consumers
/// must therefore treat the value as an optional hint and fall back to their existing behavior when it is absent.
src/Shared/Model/KnownProperties.cs:64
- The PR description still promises a
project.assemblyNamesnapshot property from #19136, but this change definesproject.targetNameand the extension consumes that different wire contract. Update the description and linked-contract wording to nameTargetName/project.targetName, so downstream consumers are not directed to a property that this code never emits.
- Files reviewed: 42/43 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
Only .NET? |
Summary
Adds a VS Code Attach debugger resource action for running .NET project resources in the Aspire view.
Fixes #18538.
Changes
ResourceDebuggerExtension.project.targetNameresource snapshot property and uses it for the CoreCLR attach process name when available.TargetPathfor older AppHosts that do not reportproject.targetName.Target-name resolution
VS Code attaches by process name, which follows the project output target name, not necessarily the project filename or raw assembly name. Reading
<AssemblyName>out of the.csprojas raw XML cannot see defaults,Directory.Build.props, imports, conditions, or SDK rewrites.This PR exposes
project.targetNameas an MSBuild-evaluated resource snapshot property. The extension consumes that property first and usesgetDotNetTargetPathas the compatibility fallback when older AppHosts omit it.Validation
cd extension && yarn compile-testscd extension && yarn lintcd extension && yarn unit-test(1461 passing,4 pending)