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:
- A new dispatch (analogous to
TryCreateDataFactoryElementTypeFromUnion) that handles known external identities for models, OR
- 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.
Summary
AzureTypeFactory.CreateCSharpTypeCoreonly handles identity-aliased external types when the input is anInputUnionType(and only forAzure.Core.Expressions.DataFactoryElement). When the same@@alternateType(Model, { identity: "..." }, "csharp")pattern is applied to anInputModelType, 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-specsspecification/datafactory/resource-manager/Microsoft.DataFactory/DataFactory/client.tsp(lines 661-681),Azure.ResourceManager.DataFactoryaliases three TSP models to external Azure.Core.Expressions.DataFactory types:Steps:
Concrete cases
A.
ZohoLinkedService.AccessTokenis droppedTypeSpec (
models.tsp:17623-17660):Swagger (
stable/2018-06-01/openapi.json:35189-35216) confirmsaccessToken: { $ref: '#/definitions/SecretBase' }.Main branch (AutoRest baseline)
Azure.ResourceManager.DataFactory.net8.0.cs:Local MPG-generated
Azure.ResourceManager.DataFactory.net8.0.cs(this branch):Inspection of the internal flattened-source type (
src/Generated/Models/ZohoLinkedServiceTypeProperties.cslines 34-43) confirms its constructor does not include anaccessTokenparameter, and the property is missing entirely. TheaccessTokenJSON field instead falls into_additionalBinaryDataPropertiesduring deserialization.B.
ZohoObjectDatasetconstructor loses its required parameterTypeSpec (
models.tsp:4573-4618):Main branch:
Local MPG-generated:
Root cause
eng/packages/http-client-csharp/generator/Azure.Generator/src/AzureTypeFactory.cs:The
InputUnionTypepath correctly recognisesExternal.IdentityforAzure.Core.Expressions.DataFactoryElement. TheInputModelTypepath never readsinputModelType.External?.Identity, so identity-aliased models fall through tobase.CreateCSharpTypeCore, which returnsnull(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 forResourceIdentifier/AzureLocation/ResponseError/ETag, with no extensibility point for additional packages.Impact
Scope across
sdk/datafactory/Azure.ResourceManager.DataFactory(agit diffof net8.0 API between local generation and main, restricted to lines mentioning the three external types):password,clientSecret,accountKey,accessToken,privateKey, ...), every Dataset's requiredLinkedServiceName, and theLinkedServiceReferenceargument on ~133 backward-compatible constructorsAny 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 consultinputModelType.External?.Identityand resolve via:TryCreateDataFactoryElementTypeFromUnion) that handles known external identities for models, ORKnownAzureTypesregistry /CreateFrameworkTypeswitch covering at least:Azure.Core.Expressions.DataFactory.DataFactorySecretAzure.Core.Expressions.DataFactory.DataFactoryLinkedServiceReferenceAzure.Core.Expressions.DataFactory.DataFactorySecretStringA 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_additionalBinaryDataPropertiesdictionary (which already preserves the raw JSON across roundtrip). Each customization file links back to this issue.