Description
C# date-time property normalization can generate invalid MRW JSON deserialization when the model's constructor parameter name is preserved from the last contract.
This was found while validating Azure/azure-sdk-for-net#62490. That PR updates @typespec/http-client-csharp from 1.0.0-alpha.20260819.14 to 1.0.0-alpha.20260825.9, whose source is commit 210f84c / #11751.
For existing management models, properties such as StartOn and EndOn are normalized to StartsOn and EndsOn, while constructor back-compat preserves the previously generated parameter names startOn and endOn. The MRW deserializer then inconsistently uses the restored constructor parameter names and the renamed property variable expressions.
The resulting generated code can:
- assign JSON values to undeclared
startOn/endOn locals, causing compilation errors; and
- pass
default to the full constructor instead of the parsed values.
Example from AzureReachabilityReportContent.Serialization.cs:
// The startOn/endOn declarations are missing.
foreach (var prop in element.EnumerateObject())
{
if (prop.NameEquals("startTime"u8))
{
startOn = prop.Value.GetDateTimeOffset("O");
continue;
}
if (prop.NameEquals("endTime"u8))
{
endOn = prop.Value.GetDateTimeOffset("O");
continue;
}
}
return new AzureReachabilityReportContent(
providerLocation,
providers ?? new ChangeTrackingList<string>(),
azureLocations ?? new ChangeTrackingList<AzureLocation>(),
default,
default,
additionalBinaryDataProperties);
The model constructor itself still has the expected slots:
internal AzureReachabilityReportContent(
AzureReachabilityReportLocation providerLocation,
IList<string> providers,
IList<AzureLocation> azureLocations,
DateTimeOffset startOn,
DateTimeOffset endOn,
IDictionary<string, BinaryData> additionalBinaryDataProperties)
Therefore this is not missing input-model information. It is a mismatch between the normalized property identity and the back-compat-restored constructor parameter used by deserialization.
Suspected area
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs, particularly:
GetPropertyVariableDeclarations
BuildDeserializePropertiesStatements
GetSerializationCtorParameterValues
These paths should use one stable local/parameter identity when a constructor parameter name differs from its associated property's generated name.
A regression test should combine:
- a last-contract constructor parameter named
startOn or endOn;
- a current property normalized to
StartsOn or EndsOn; and
- MRW JSON deserialization.
The generated deserializer should declare, assign, and pass the same local without replacing the parsed value with default.
The separate question of whether the prior StartOn/EndOn property API should be preserved can be handled independently; regardless of that policy, generated deserialization must compile and retain the parsed values.
Affected generated files
Azure/azure-sdk-for-net#62490 contains the following 11 affected files:
sdk/avs/Azure.ResourceManager.Avs/src/Generated/Models/VMwareFirewallLicenseProperties.Serialization.cs (endOn)
sdk/avs/Azure.ResourceManager.Avs/src/Generated/Models/Vcf5License.Serialization.cs (endOn)
sdk/consumption/Azure.ResourceManager.Consumption/src/Generated/Models/BudgetTimePeriod.Serialization.cs (startOn)
sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/BenefitUtilizationSummariesContent.Serialization.cs (startOn, endOn)
sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/BudgetTimePeriod.Serialization.cs (startOn)
sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/ScheduleProperties.Serialization.cs (startOn, endOn)
sdk/databox/Azure.ResourceManager.DataBox/src/Generated/Models/ShipmentPickUpContent.Serialization.cs (startOn, endOn)
sdk/databoxedge/Azure.ResourceManager.DataBoxEdge/src/Generated/Models/PeriodicTimerSourceInfo.Serialization.cs (startOn)
sdk/dataprotection/Azure.ResourceManager.DataProtectionBackup/src/Generated/Models/DataProtectionBackupJobProperties.Serialization.cs (startOn)
sdk/dataprotection/Azure.ResourceManager.DataProtectionBackup/src/Generated/Models/RestorableTimeRange.Serialization.cs (startOn, endOn)
sdk/network/Azure.ResourceManager.Network/src/Generated/Models/AzureReachabilityReportContent.Serialization.cs (startOn, endOn)
Inline examples are also visible in these review threads:
Package/source chain
- Previous management emitter:
@azure-typespec/http-client-csharp-mgmt@1.0.0-alpha.20260824.1
@typespec/http-client-csharp@1.0.0-alpha.20260819.14
- source commit
365ec52b50b82cd9e1e037de4c6fcd5de7e32e90
- Failing management emitter:
@azure-typespec/http-client-csharp-mgmt@1.0.0-alpha.20260826.4
@typespec/http-client-csharp@1.0.0-alpha.20260825.9
- source commit
210f84c0dee6cfb8226ce95700562c9bf0922822
- by copilot
Description
C# date-time property normalization can generate invalid MRW JSON deserialization when the model's constructor parameter name is preserved from the last contract.
This was found while validating Azure/azure-sdk-for-net#62490. That PR updates
@typespec/http-client-csharpfrom1.0.0-alpha.20260819.14to1.0.0-alpha.20260825.9, whose source is commit 210f84c / #11751.For existing management models, properties such as
StartOnandEndOnare normalized toStartsOnandEndsOn, while constructor back-compat preserves the previously generated parameter namesstartOnandendOn. The MRW deserializer then inconsistently uses the restored constructor parameter names and the renamed property variable expressions.The resulting generated code can:
startOn/endOnlocals, causing compilation errors; anddefaultto the full constructor instead of the parsed values.Example from
AzureReachabilityReportContent.Serialization.cs:The model constructor itself still has the expected slots:
Therefore this is not missing input-model information. It is a mismatch between the normalized property identity and the back-compat-restored constructor parameter used by deserialization.
Suspected area
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs, particularly:GetPropertyVariableDeclarationsBuildDeserializePropertiesStatementsGetSerializationCtorParameterValuesThese paths should use one stable local/parameter identity when a constructor parameter name differs from its associated property's generated name.
A regression test should combine:
startOnorendOn;StartsOnorEndsOn; andThe generated deserializer should declare, assign, and pass the same local without replacing the parsed value with
default.The separate question of whether the prior
StartOn/EndOnproperty API should be preserved can be handled independently; regardless of that policy, generated deserialization must compile and retain the parsed values.Affected generated files
Azure/azure-sdk-for-net#62490 contains the following 11 affected files:
sdk/avs/Azure.ResourceManager.Avs/src/Generated/Models/VMwareFirewallLicenseProperties.Serialization.cs(endOn)sdk/avs/Azure.ResourceManager.Avs/src/Generated/Models/Vcf5License.Serialization.cs(endOn)sdk/consumption/Azure.ResourceManager.Consumption/src/Generated/Models/BudgetTimePeriod.Serialization.cs(startOn)sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/BenefitUtilizationSummariesContent.Serialization.cs(startOn,endOn)sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/BudgetTimePeriod.Serialization.cs(startOn)sdk/costmanagement/Azure.ResourceManager.CostManagement/src/Generated/Models/ScheduleProperties.Serialization.cs(startOn,endOn)sdk/databox/Azure.ResourceManager.DataBox/src/Generated/Models/ShipmentPickUpContent.Serialization.cs(startOn,endOn)sdk/databoxedge/Azure.ResourceManager.DataBoxEdge/src/Generated/Models/PeriodicTimerSourceInfo.Serialization.cs(startOn)sdk/dataprotection/Azure.ResourceManager.DataProtectionBackup/src/Generated/Models/DataProtectionBackupJobProperties.Serialization.cs(startOn)sdk/dataprotection/Azure.ResourceManager.DataProtectionBackup/src/Generated/Models/RestorableTimeRange.Serialization.cs(startOn,endOn)sdk/network/Azure.ResourceManager.Network/src/Generated/Models/AzureReachabilityReportContent.Serialization.cs(startOn,endOn)Inline examples are also visible in these review threads:
Package/source chain
@azure-typespec/http-client-csharp-mgmt@1.0.0-alpha.20260824.1@typespec/http-client-csharp@1.0.0-alpha.20260819.14365ec52b50b82cd9e1e037de4c6fcd5de7e32e90@azure-typespec/http-client-csharp-mgmt@1.0.0-alpha.20260826.4@typespec/http-client-csharp@1.0.0-alpha.20260825.9210f84c0dee6cfb8226ce95700562c9bf0922822- by copilot