Skip to content

[Mgmt][CodeGen] AzureTypeFactory drops properties whose model type uses identity-aliased @@alternateType (InputModelType.External.Identity) #59298

@mzhongl524

Description

@mzhongl524

Summary

AzureTypeFactory.CreateCSharpTypeCore only handles identity-aliased external types when the input is an InputUnionType (and only for Azure.Core.Expressions.DataFactoryElement). When the same @@alternateType(Model, { identity: "..." }, "csharp") pattern is applied to an InputModelType, the generator has no code path to resolve the alternate identity. Consequently every property whose type is one of those externally-aliased models is silently dropped from the generated C# model (no diagnostic, no warning).

Repro

In azure-rest-api-specs specification/datafactory/resource-manager/Microsoft.DataFactory/DataFactory/client.tsp (lines 661-681), Azure.ResourceManager.DataFactory aliases three TSP models to external Azure.Core.Expressions.DataFactory types:

// Map SecretBase and LinkedServiceReference to the external
// Azure.Core.Expressions.DataFactory types so baseline API surface matches
// (avoids exposing local DataFactorySecret/Reference classes).
@@alternateType(
  SecretBase,
  { identity: "Azure.Core.Expressions.DataFactory.DataFactorySecret" },
  "csharp"
);
@@alternateType(
  LinkedServiceReference,
  { identity: "Azure.Core.Expressions.DataFactory.DataFactoryLinkedServiceReference" },
  "csharp"
);
@@alternateType(
  SecureString,
  { identity: "Azure.Core.Expressions.DataFactory.DataFactorySecretString" },
  "csharp"
);

Steps:

cd sdk/datafactory/Azure.ResourceManager.DataFactory
dotnet build /t:GenerateCode /p:LocalSpecRepo="<path>/specification/datafactory/resource-manager/Microsoft.DataFactory/DataFactory" /p:SaveInputs=true

Concrete cases

A. ZohoLinkedService.AccessToken is dropped

TypeSpec (models.tsp:17623-17660):

model ZohoLinkedServiceTypeProperties {
  connectionProperties?: unknown;
  endpoint?: Dfe<string>;
  accessToken?: SecretBase;             // <-- aliased to DataFactorySecret
  useEncryptedEndpoints?: Dfe<boolean>;
  ...
}

Swagger (stable/2018-06-01/openapi.json:35189-35216) confirms accessToken: { $ref: '#/definitions/SecretBase' }.

Main branch (AutoRest baseline) Azure.ResourceManager.DataFactory.net8.0.cs:

public partial class ZohoLinkedService : DataFactoryLinkedServiceProperties
{
    public ZohoLinkedService() { }
    public DataFactorySecret AccessToken { get; set; }                   // ✅ present
    ...
}

Local MPG-generated Azure.ResourceManager.DataFactory.net8.0.cs (this branch):

public partial class ZohoLinkedService : DataFactoryLinkedServiceProperties
{
    public ZohoLinkedService() { }
    // ❌ no AccessToken!
    public BinaryData ConnectionProperties { get; set; }
    public string EncryptedCredential { get; set; }
    public DataFactoryElement<string> Endpoint { get; set; }
    ...
}

Inspection of the internal flattened-source type (src/Generated/Models/ZohoLinkedServiceTypeProperties.cs lines 34-43) confirms its constructor does not include an accessToken parameter, and the property is missing entirely. The accessToken JSON field instead falls into _additionalBinaryDataProperties during deserialization.

B. ZohoObjectDataset constructor loses its required parameter

TypeSpec (models.tsp:4573-4618):

model Dataset {
  ...Record<unknown>;
  type: string;
  ...
  linkedServiceName: LinkedServiceReference;  // <-- required, aliased
  ...
}

Main branch:

protected DataFactoryDatasetProperties(DataFactoryLinkedServiceReference linkedServiceName) { }
public DataFactoryLinkedServiceReference LinkedServiceName { get; set; }

public partial class ZohoObjectDataset : DataFactoryDatasetProperties
{
    public ZohoObjectDataset(DataFactoryLinkedServiceReference linkedServiceName)
        : base(default(DataFactoryLinkedServiceReference)) { }
    ...
}

Local MPG-generated:

// DataFactoryDatasetProperties no longer has LinkedServiceName at all
private protected DataFactoryDatasetProperties(string datasetType) { ... }

public partial class ZohoObjectDataset : DataFactoryDatasetProperties
{
    public ZohoObjectDataset() : base("ZohoObject") { }   // ❌ parameterless only
    ...
}

Root cause

eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureTypeFactory.cs:

protected override CSharpType? CreateCSharpTypeCore(InputType inputType)
{
    if (inputType is InputPrimitiveType inputPrimitiveType) { ... }
    else if (inputType is InputModelType inputModelType)
    {
        if (KnownAzureTypes.TryGetKnownType(inputModelType.CrossLanguageDefinitionId, out var knownType))
            return knownType;
        // ❌ Never consults inputModelType.External?.Identity
    }
    else if (inputType is InputArrayType inputArrayType) { ... }
    else if (inputType is InputUnionType inputUnionType)
    {
        var dataFactoryElementType = TryCreateDataFactoryElementTypeFromUnion(inputUnionType);
        if (dataFactoryElementType != null) return dataFactoryElementType;
    }
    return base.CreateCSharpTypeCore(inputType);
}

private CSharpType? TryCreateDataFactoryElementTypeFromUnion(InputUnionType inputUnionType)
{
    if (inputUnionType.External?.Identity != AzureClientGenerator.DataFactoryElementIdentity) // ✅ only this one
        return null;
    ...
}

The InputUnionType path correctly recognises External.Identity for Azure.Core.Expressions.DataFactoryElement. The InputModelType path never reads inputModelType.External?.Identity, so identity-aliased models fall through to base.CreateCSharpTypeCore, which returns null (because TCGC excluded the model from generation due to the alternateType), and the consumer property is silently omitted.

CreateFrameworkType (AzureTypeFactory.cs:148-158) only hard-codes a 4-entry switch for ResourceIdentifier/AzureLocation/ResponseError/ETag, with no extensibility point for additional packages.

Impact

Scope across sdk/datafactory/Azure.ResourceManager.DataFactory (a git diff of net8.0 API between local generation and main, restricted to lines mentioning the three external types):

  • 167 model classes affected
  • 337 public API members (properties + constructors) missing
  • Includes every LinkedService secret (password, clientSecret, accountKey, accessToken, privateKey, ...), every Dataset's required LinkedServiceName, and the LinkedServiceReference argument on ~133 backward-compatible constructors

Any future GA service that wants to alternateType a model to an external NuGet type (rather than the built-in DataFactoryElement<T> union case) will hit the same bug.

Proposed fix

In AzureTypeFactory.CreateCSharpTypeCore, also consult inputModelType.External?.Identity and resolve via:

  1. A new dispatch (analogous to TryCreateDataFactoryElementTypeFromUnion) that handles known external identities for models, OR
  2. An expanded KnownAzureTypes registry / CreateFrameworkType switch covering at least:
    • Azure.Core.Expressions.DataFactory.DataFactorySecret
    • Azure.Core.Expressions.DataFactory.DataFactoryLinkedServiceReference
    • Azure.Core.Expressions.DataFactory.DataFactorySecretString

A diagnostic for the dropped-property case would also have prevented this from being a silent failure.

Workaround in place

Until the generator is fixed, sdk/datafactory/Azure.ResourceManager.DataFactory/src/Custom/Models/ re-exposes the missing properties / constructors via partial classes that back-store through the existing _additionalBinaryDataProperties dictionary (which already preserves the raw JSON across roundtrip). Each customization file links back to this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CodeGenIssues that relate to code generationMgmtThis issue is related to a management package.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions