Summary
ATS property export currently treats C# init properties as writable because reflection reports them through PropertyInfo.CanWrite. That causes the scanner/codegen to emit set<Property> capabilities for state that is intended to be immutable after object creation.
We should change the ATS export logic so init-only properties can still be exported as readable getters, but do not produce setter capabilities.
Motivation
This came up in #16403 (comment) while reviewing the ATS-first exported capability surface. PipelineStep.Name and PipelineStep.Description are public C# init properties. Exporting them directly would cause ATS to generate setName / setDescription, so the PR used internal getter-only projection properties as a targeted workaround.
The intent of init is that the object is immutable after construction. If ATS exports an init accessor as a normal set capability, polyglot consumers get a mutator that breaks that assumption. Handling this in the core ATS scanner is clearer and less noisy than requiring every init-only property to add a separate projection solely to avoid setter generation.
Proposed behavior
- When scanning exported properties, detect C#
init-only setters and exclude the generated ATS setter capability.
- Continue generating getter capabilities for readable init-only properties.
- Continue generating setter capabilities for ordinary mutable
set properties.
- Where possible, remove or avoid ATS-only projection properties whose only purpose is suppressing setters for init-only state.
Implementation note: an init-only setter can be detected from the setter metadata, for example by checking for the required System.Runtime.CompilerServices.IsExternalInit modifier on the setter return parameter.
Acceptance criteria
[AspireExport] / ExposeProperties does not emit set<Property> ATS capabilities for C# init-only properties.
- Existing mutable properties with normal setters still emit setters and continue to dispatch correctly.
- Generated polyglot surfaces no longer expose mutating APIs for init-only state.
- ATS export/generated-output changes are reflected through the appropriate generated artifacts and polyglot apphost updates.
Summary
ATS property export currently treats C#
initproperties as writable because reflection reports them throughPropertyInfo.CanWrite. That causes the scanner/codegen to emitset<Property>capabilities for state that is intended to be immutable after object creation.We should change the ATS export logic so
init-only properties can still be exported as readable getters, but do not produce setter capabilities.Motivation
This came up in #16403 (comment) while reviewing the ATS-first exported capability surface.
PipelineStep.NameandPipelineStep.Descriptionare public C#initproperties. Exporting them directly would cause ATS to generatesetName/setDescription, so the PR used internal getter-only projection properties as a targeted workaround.The intent of
initis that the object is immutable after construction. If ATS exports aninitaccessor as a normalsetcapability, polyglot consumers get a mutator that breaks that assumption. Handling this in the core ATS scanner is clearer and less noisy than requiring every init-only property to add a separate projection solely to avoid setter generation.Proposed behavior
init-only setters and exclude the generated ATS setter capability.setproperties.Implementation note: an init-only setter can be detected from the setter metadata, for example by checking for the required
System.Runtime.CompilerServices.IsExternalInitmodifier on the setter return parameter.Acceptance criteria
[AspireExport]/ExposePropertiesdoes not emitset<Property>ATS capabilities for C# init-only properties.