-
Notifications
You must be signed in to change notification settings - Fork 5.1k
[Mgmt Generator] Multi-scope resource generates duplicate GetXxxResource factory methods (CS0111) #57645
Description
Bug Description
The MPG generator (Azure Management Plane Generator) produces duplicate identical GetXxxResource factory methods when a TypeSpec spec defines a multi-scope resource using Legacy.ExtensionOperations with multiple interfaces. This causes CS0111 ("Type already defines a member with the same parameter types") compilation errors.
Spec Structure
Repo: Azure/azure-rest-api-specs
Path: specification/kubernetesconfiguration/resource-manager/Microsoft.KubernetesConfiguration/extensionTypes/
Commit: 8d0a948edb8a860ea00768533210f98634a0870e
ExtensionType.tsp
Defines the ExtensionType resource model with 2 interfaces at different scopes:
// Scope 1: Subscription/Location
// Path: /subscriptions/{subscriptionId}/providers/Microsoft.KubernetesConfiguration/locations/{location}/extensionTypes/{extensionTypeName}
alias ExtensionTypeOps = Azure.ResourceManager.Legacy.ExtensionOperations<
{ ...ApiVersionParameter; ...SubscriptionIdParameter; @path @segment("providers") @key providerNamespace: "Microsoft.KubernetesConfiguration"; ...LocationParameter; },
{},
{ @path @segment("extensionTypes") @key @pattern("^[a-zA-Z][a-zA-Z0-9-_]*$") extensionTypeName: string; }
>;
@armResourceOperations(#{ omitTags: true })
interface ExtensionTypes { ... }
// Scope 2: ResourceGroup/Cluster
// Path: /subscriptions/{subscriptionId}/resourceGroups/{rg}/providers/{clusterRp}/{clusterResourceName}/{clusterName}/providers/Microsoft.KubernetesConfiguration/extensionTypes/{extensionTypeName}
alias ExtensionTypeOperationGroupOps = Azure.ResourceManager.Legacy.ExtensionOperations<
{ ...ApiVersionParameter; ...SubscriptionIdParameter; ...ResourceGroupParameter; @path @segment("providers") @key clusterRp: string; @key @path clusterResourceName: string; @key @path clusterName: string; },
{ ...Extension.ExtensionProviderNamespace<ExtensionType>; ...ParentKeysOf<ExtensionType>; },
{ ...Extension.ExtensionProviderNamespace<ExtensionType>; ...KeysOf<ExtensionType>; }
>;
@armResourceOperations(#{ omitTags: true })
interface ExtensionTypeOperationGroup { ... }ExtensionTypeVersionForReleaseTrain.tsp
Defines a child resource @parentResource(ExtensionType) with another 2 interfaces at different scopes:
interface ExtensionTypeVersionForReleaseTrains { ... } // Location scope
interface ExtensionTypeVersionForReleaseTrainOperationGroup { ... } // Cluster scopeback-compatible.tsp
Uses @@clientLocation to consolidate operations:
@@clientLocation(ExtensionTypeOperationGroup.get, ExtensionTypes);
@@clientLocation(ExtensionTypeOperationGroup.list, ExtensionTypes);
@@clientLocation(ExtensionTypeVersionForReleaseTrains.getVersion, ExtensionTypes);
@@clientLocation(ExtensionTypeVersionForReleaseTrains.listVersions, ExtensionTypes);
@@clientLocation(ExtensionTypeVersionForReleaseTrainOperationGroup.clusterGetVersion, ExtensionTypes);
@@clientLocation(ExtensionTypeVersionForReleaseTrainOperationGroup.clusterListVersions, ExtensionTypes);But @@clientLocation only moves operations (Read/List), not the resource factory methods.
Swagger (Generated OpenAPI)
The swagger produces 4 operation groups that all reference the same ExtensionType schema:
ExtensionTypes_LocationGet/ExtensionTypes_LocationList(subscription/location scope)ExtensionTypeOperationGroup_Get/ExtensionTypeOperationGroup_List(cluster scope)ExtensionTypeVersionForReleaseTrains_GetVersion/..._ListVersions(location scope)ExtensionTypeVersionForReleaseTrainOperationGroup_ClusterGetVersion/..._ClusterListVersions(cluster scope)
All operation groups share the same resource model ExtensionType, which maps to the single C# class ExtensionTypeInterfaceResource.
Generated Code (Bug)
After running dotnet build /t:GenerateCode, the generator produces 4 identical copies of each factory method:
In KubernetesConfigurationExtensionTypesExtensions.cs:
// Copy 1 (from ExtensionTypes interface)
public static ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(this ArmClient client, ResourceIdentifier id) { ... }
// Copy 2 (from ExtensionTypeOperationGroup interface)
public static ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(this ArmClient client, ResourceIdentifier id) { ... }
// Copy 3 (from ExtensionTypeVersionForReleaseTrains interface)
public static ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(this ArmClient client, ResourceIdentifier id) { ... }
// Copy 4 (from ExtensionTypeVersionForReleaseTrainOperationGroup interface)
public static ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(this ArmClient client, ResourceIdentifier id) { ... }In MockableKubernetesConfigurationExtensionTypesArmClient.cs:
// Same 4 identical copies of:
public virtual ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(ResourceIdentifier id) { ... }Expected Behavior
The generator should deduplicate GetXxxResource factory methods. Regardless of how many interfaces/scopes reference the same resource model, only one copy of each factory method should be generated.
Current Workaround
SDK-side workaround using [CodeGenSuppress] + custom partial class implementation:
[CodeGenSuppress("GetExtensionTypeInterfaceResource", typeof(ArmClient), typeof(ResourceIdentifier))]
public static partial class KubernetesConfigurationExtensionTypesExtensions
{
public static ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(this ArmClient client, ResourceIdentifier id) { ... }
}
[CodeGenSuppress("GetExtensionTypeInterfaceResource", typeof(ResourceIdentifier))]
public partial class MockableKubernetesConfigurationExtensionTypesArmClient
{
public virtual ExtensionTypeInterfaceResource GetExtensionTypeInterfaceResource(ResourceIdentifier id) { ... }
}Affected Component
eng/packages/http-client-csharp-mgmt — resource factory method generation logic. The deduplication should likely happen when collecting resource factory methods across multiple interfaces/scopes in resolve-arm-resources-converter.ts or the extension method generation code.