Skip to content

Switch ATS attribute discovery to name-based matching for third-party support#14977

Open
sebastienros wants to merge 2 commits intorelease/13.2from
sebros/ats-attributes
Open

Switch ATS attribute discovery to name-based matching for third-party support#14977
sebastienros wants to merge 2 commits intorelease/13.2from
sebros/ats-attributes

Conversation

@sebastienros
Copy link
Member

Description

Switch ATS (Aspire Type System) attribute discovery from concrete type matching via GetCustomAttribute<T>() to name-based matching via CustomAttributeData. This allows third-party integration authors to define their own copies of AspireExport, AspireExportIgnore, AspireDto, and AspireUnion attributes in any namespace without requiring a package reference to Aspire.Hosting.

When we ship the official attribute types publicly, anyone who created custom mock types will not be broken — both official and custom attributes are recognized by name.

Changes

  • AttributeDataReader.cs — New internal helper with adapter types (AspireExportData, AspireUnionData) that parse CustomAttributeData by type name. Constructor args are matched by signature (arity + type) rather than parameter name for maximum third-party compatibility.
  • AtsCapabilityScanner.cs — Updated all 11 helper methods and method signatures (CreateTypeInfo, CreateCapabilityInfo, ShouldExportMember, CreateUnionTypeRef) to use the adapter types.
  • ThirdPartyAtsAttributes.md — Documentation showing third-party authors how to define their own attribute types.
  • Tests — 11 new tests including third-party mock attributes in a separate namespace, renamed constructor parameter verification, and full ScanAssemblies integration tests.

Validation

  • All 33 ATS scanner tests pass (22 existing + 11 new)
  • End-to-end verified: aspire init --language typescript + aspire add Aspire.Hosting.Redis generates correct TypeScript SDK with all Redis methods
  • TypeScript compilation of generated SDK passes with zero errors

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

sebastienros and others added 2 commits March 5, 2026 07:42
…buteData

Replace concrete GetCustomAttribute<T>() calls in AtsCapabilityScanner with
CustomAttributeData-based name matching. This allows third-party integration
authors to define their own copies of AspireExport, AspireExportIgnore,
AspireDto, and AspireUnion attributes in any namespace without referencing
Aspire.Hosting.

Changes:
- Add AttributeDataReader with adapter types (AspireExportData, AspireUnionData)
  that wrap CustomAttributeData and provide typed property access
- Update all 11 helper methods in AtsCapabilityScanner to use name-based lookup
- Update CreateTypeInfo, CreateCapabilityInfo, ShouldExportMember, and
  CreateUnionTypeRef to use adapter types instead of concrete attribute types
- Add ThirdPartyAtsAttributes.md documenting how third-party authors create
  their own attribute types
- Add 10 tests proving cross-namespace attribute discovery works, including
  full integration tests via ScanAssemblies

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… name

Replace parameter-name-based matching ("id", "type") with
signature-based matching (arity + argument type) so third-party
attribute copies with different constructor parameter names are
still parsed correctly.

Add test with RenamedParam mock attribute that uses "name" instead
of "id" and "targetType" instead of "type" to verify this.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros
Copy link
Member Author

@davidfowl Do we want to ship a public nuget packages with these types before 13.2? (Aspire.Hosting 13.2 will have these). IMO it's not necessary, they can use the sample provided in this PR to start annotating their integrations until 13.2 is available.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@sebastienros sebastienros reopened this Mar 5, 2026
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Mar 5, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14977

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14977"

@github-actions
Copy link
Contributor

github-actions bot commented Mar 5, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit 99adc32:

Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AgentInitCommand_WithMalformedMcpJson_ShowsErrorAndExitsNonZero ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateStartWaitAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ❌ Upload failed
LogsCommandShowsResourceLogs ❌ Upload failed
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ❌ Upload failed
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ❌ Upload failed
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
TypeScriptAppHostWithProjectReferenceIntegration ❌ Upload failed

📹 Recordings uploaded automatically from CI run #22729667261

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants