Annotation-Based Open Discriminated Union for Aspire Resources #8984
Labels
area-app-model
Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication
breaking-change
Issue or PR that represents a breaking API or functional change over a prerelease.
Today every concrete resource class—
ProjectResource
,ContainerResource
,AzureServiceBusResource
, etc.—owns state in its own fields.When real workflows demand the same logical resource appear differently in run-mode and publish-mode, our model currently must
That breaks identity (two resource IDs), scatters logs, confuses diff tooling, and forces hacks inside helpers such as
RunAsContainer()
,RunAsEmulator()
, andPublishAsDockerFile()
.We already tie container identity to the annotation-collection reference; this proposal finishes that idea for all resources:
ResourceTypeAnnotation.ResourceKind : Type
— declares the current shape..NET Project
Identity never changes; we simply switch the tag.
Code sketches (same helpers, new engine)
Execution plan (high-level)
Phase A — helper façade
IsKind<T>()
,TryGet<T>()
(initial impl =is/as
).is
,as
,OfType<T>()
in the codebase.Phase B — tag & identity
ResourceTypeAnnotation
andResource.ResourceKind
.Equals
/GetHashCode
now rely on the annotation-collection reference.Phase C — move data to annotations
*Annotation
classes (e.g.ContainerEntryPointAnnotation
).Annotation collections become read-only after model-build; cloning must be explicit.
Helper API details
Every resource kind must expose a
(string name, ResourceAnnotationCollection ann)
constructor; an analyzer will enforce this.Trade-offs & potential issues
Mitigation: default branches plus analyzer checks.
Mitigation: cache
typeof(T)
comparisons and profile.is/as
– will break when the tag diverges from CLR type.Mitigation: analyzer package + migration docs; optional runtime guard.
Mitigation: freeze collection reference after build; mutations through
WithAnnotation
.Mitigation: analyzer + project template.
Mitigation: land in next major release; debug shim to detect old behaviour.
Unsolved / open design gaps
View-specific members remain callable after a view switch.
Example: you create an
AzureBicepResource
, callRunAsEmulator()
, so it is now viewed as a container, yetbicepResource.Outputs["primaryKey"]
is still accessible—even though those outputs are meaningless in run-mode.Unanswered questions:
These remain open and must be tracked as follow-up work once the union mechanics are in place.
See #7251 for an initial prototype
The text was updated successfully, but these errors were encountered: