Description
The C# generator has SystemObjectModelProvider, which is a useful building block for mapping an input model to an existing framework/system model while still allowing derived generated models to use it as BaseModelProvider. However, Azure management-plane generation still needs a custom MPG visitor (InheritableSystemObjectModelVisitor) to repair several behaviors after mapping ARM common types like Resource, ProxyResource, and TrackedResource to framework types such as ResourceData and TrackedResourceData.
We would like MTG/ClientModel to provide first-class support for inheritable system model replacement so MPG can remove or significantly shrink this visitor.
Current workaround in MPG
In Azure/azure-sdk-for-net#56634, MPG uses InheritableSystemObjectModelVisitor to:
- Register framework
CSharpType aliases in CSharpTypeMap so custom-code base types like TrackedResourceData resolve back to the mapped SystemObjectModelProvider.
- Repair
SystemObjectModelProvider namespace after generic namespace visitors run.
- Remove model factory methods returning known framework management types.
- Manually remove inherited properties from derived models, including wire-name matches such as a derived
Name0 property whose serialized name is name, because the framework base already owns Name.
- Strip orphaned
virtual modifiers after removing inherited duplicate properties.
Gap in MTG today
SystemObjectModelProvider : ModelProvider already helps with some inheritance behavior:
- It can serve as
BaseModelProvider.
- It sets
ShouldSkipDerivedModelProperties = true.
- It does not emit fields or serialization providers for the framework type.
ModelProvider.BuildProperties() skips derived properties whose C# property name matches a base property from a provider marked ShouldSkipDerivedModelProperties.
But this is not enough for ARM-style common types:
1. Wire-name based property dedup is missing
MTG skips inherited properties by C# property name. MPG also needs wire-name equivalence.
Example:
- Framework base has
Name with wire name name.
- Derived input model has a generated C# property
Name0 but serialized/wire name name.
- The derived property should be removed because the framework base already represents that wire property.
Without this, generated output can duplicate ARM base properties as renamed properties like Name0.
2. Framework/non-framework CSharpType alias lookup is fragile
Custom code can resolve a base type like TrackedResourceData as a framework CSharpType, while the mapped system provider may be keyed differently. MTG should make the system replacement discoverable under all equivalent CSharpType forms, or compare framework/system replacement types consistently in BuildBaseModelProvider().
3. Namespace rewriting should not corrupt system providers
Generic namespace visitors can rewrite provider namespaces to the SDK namespace. A system/framework provider should keep its framework namespace or otherwise be immune to normal generated-model namespace rewriting.
4. Model factory methods should not be emitted for framework replacements
If an input model is replaced by a framework/system type, model factory methods returning that framework replacement should be skipped by default. MPG currently filters them out.
5. Constructor/field/serialization behavior should fully account for system bases
Once a generator maps an input model to an inheritable framework base, derived models should not duplicate inherited fields/properties/constructor parameters/serialization overrides, including the wire-name equivalence case above.
Desired behavior
A generator should be able to register something equivalent to:
Known ARM model "TrackedResource" -> framework type TrackedResourceData
Known ARM model "Resource" -> framework type ResourceData
Then MTG should handle derived generated models correctly without a management-plane visitor manually walking and editing properties.
Suggested test case
Add a ClientModel/MTG test with:
- A system base input model representing
ResourceData or TrackedResourceData, with properties like id, name, type, tags, location.
- A derived generated model with a property named
name0 whose serialized name is name, plus a normal service-specific property.
- The base model mapped to a
SystemObjectModelProvider/framework type.
Expected:
- The derived generated model does not emit
Name0.
- It does not duplicate base fields or constructor parameters.
- Serialization methods call/override appropriately for a system base.
- Model factory methods for the framework replacement type are not generated.
- The system provider keeps the framework namespace.
Context
This is needed to simplify Azure management-plane generation and eventually remove more of InheritableSystemObjectModelVisitor from MPG.
Description
The C# generator has
SystemObjectModelProvider, which is a useful building block for mapping an input model to an existing framework/system model while still allowing derived generated models to use it asBaseModelProvider. However, Azure management-plane generation still needs a custom MPG visitor (InheritableSystemObjectModelVisitor) to repair several behaviors after mapping ARM common types likeResource,ProxyResource, andTrackedResourceto framework types such asResourceDataandTrackedResourceData.We would like MTG/ClientModel to provide first-class support for inheritable system model replacement so MPG can remove or significantly shrink this visitor.
Current workaround in MPG
In Azure/azure-sdk-for-net#56634, MPG uses
InheritableSystemObjectModelVisitorto:CSharpTypealiases inCSharpTypeMapso custom-code base types likeTrackedResourceDataresolve back to the mappedSystemObjectModelProvider.SystemObjectModelProvidernamespace after generic namespace visitors run.Name0property whose serialized name isname, because the framework base already ownsName.virtualmodifiers after removing inherited duplicate properties.Gap in MTG today
SystemObjectModelProvider : ModelProvideralready helps with some inheritance behavior:BaseModelProvider.ShouldSkipDerivedModelProperties = true.ModelProvider.BuildProperties()skips derived properties whose C# property name matches a base property from a provider markedShouldSkipDerivedModelProperties.But this is not enough for ARM-style common types:
1. Wire-name based property dedup is missing
MTG skips inherited properties by C# property name. MPG also needs wire-name equivalence.
Example:
Namewith wire namename.Name0but serialized/wire namename.Without this, generated output can duplicate ARM base properties as renamed properties like
Name0.2. Framework/non-framework
CSharpTypealias lookup is fragileCustom code can resolve a base type like
TrackedResourceDataas a frameworkCSharpType, while the mapped system provider may be keyed differently. MTG should make the system replacement discoverable under all equivalentCSharpTypeforms, or compare framework/system replacement types consistently inBuildBaseModelProvider().3. Namespace rewriting should not corrupt system providers
Generic namespace visitors can rewrite provider namespaces to the SDK namespace. A system/framework provider should keep its framework namespace or otherwise be immune to normal generated-model namespace rewriting.
4. Model factory methods should not be emitted for framework replacements
If an input model is replaced by a framework/system type, model factory methods returning that framework replacement should be skipped by default. MPG currently filters them out.
5. Constructor/field/serialization behavior should fully account for system bases
Once a generator maps an input model to an inheritable framework base, derived models should not duplicate inherited fields/properties/constructor parameters/serialization overrides, including the wire-name equivalence case above.
Desired behavior
A generator should be able to register something equivalent to:
Then MTG should handle derived generated models correctly without a management-plane visitor manually walking and editing properties.
Suggested test case
Add a ClientModel/MTG test with:
ResourceDataorTrackedResourceData, with properties likeid,name,type,tags,location.name0whose serialized name isname, plus a normal service-specific property.SystemObjectModelProvider/framework type.Expected:
Name0.Context
This is needed to simplify Azure management-plane generation and eventually remove more of
InheritableSystemObjectModelVisitorfrom MPG.