Generate AOT-compatible C# primitive responses - #11931
Generate AOT-compatible C# primitive responses#11931Jorge Rangel (jorgerangel-msft) with Copilot wants to merge 23 commits into
Conversation
|
Azure Pipelines: Successfully started running 1 pipeline(s). 1 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
…ection Co-authored-by: jorgerangel-msft <[email protected]>
Co-authored-by: jorgerangel-msft <[email protected]>
commit: |
There was a problem hiding this comment.
🟢 Approval recommended
The implementation covers the intended response types and includes focused generation and runtime tests.
Pull request overview
Updates the C# client generator to deserialize primitive and enum responses without reflection, enabling Native AOT compatibility while preserving BOM and nullable handling.
Changes:
- Uses typed
JsonElementreads for primitive and enum responses. - Preserves plain-text behavior and constant-format
TimeSpanconversion. - Adds generation baselines and runtime BOM coverage for sync/async enum responses.
File summaries
| File | Description |
|---|---|
TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs |
Updates generated enum deserialization. |
TestProjects/Local.Tests/ExtensibleEnumTests.cs |
Tests sync/async BOM handling. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(TimeSpanNullable).cs |
Adds nullable TimeSpan baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(TimeSpan).cs |
Updates TimeSpan baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(String).cs |
Updates string baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Single).cs |
Updates float baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Int64).cs |
Updates long baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Int32NullableAsync).cs |
Adds async nullable integer baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Int32Nullable).cs |
Adds nullable integer baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Int32Async).cs |
Adds async integer baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Int32).cs |
Updates integer baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Double).cs |
Updates double baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Decimal).cs |
Adds decimal baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(DateTimeOffset).cs |
Updates date-time baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(BooleanNullable).cs |
Adds nullable boolean baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/ScalarReturnTypeMethods(Boolean).cs |
Updates boolean baseline. |
test/Providers/TestData/ScmMethodProviderCollectionTests/PlainTextReturnTypeMethods.cs |
Verifies plain-text handling. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(True,True,True).cs |
Covers nullable extensible string enum. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(True,True,False).cs |
Covers extensible string enum. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(True,False,False).cs |
Covers fixed string enum. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(False,True,False).cs |
Covers extensible integer enum. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(False,False,True).cs |
Covers nullable fixed integer enum. |
test/Providers/TestData/ScmMethodProviderCollectionTests/EnumReturnTypeMethods(False,False,False).cs |
Covers fixed integer enum. |
test/Providers/ScmMethodProviderCollectionTests.cs |
Expands scalar and enum generation tests. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewRequiredParameterDoesNotAddBackCompatOverload.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewOptionalParameterWithReservedName.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewOptionalNonBodyParameterAddedWithPathAndHeaderParameters.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewOptionalNonBodyParameterAddedWithModelBody.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewOptionalNonBodyParameterAdded.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_NewOptionalBodyParameterDoesNotAddBackCompatOverload.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_MultipleNewOptionalNonBodyParametersAdded.cs |
Refreshes generated baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_ConvenienceMethodParamOrderChanged(Sync).cs |
Adds sync body baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_ConvenienceMethodParamOrderChanged(Async).cs |
Adds async body baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_BothMethodsParamOrderChanged(Sync).cs |
Adds sync compatibility baseline. |
test/Providers/ClientProviders/TestData/ClientProviderTests/BackCompatibility_BothMethodsParamOrderChanged(Async).cs |
Adds async compatibility baseline. |
test/Providers/ClientProviders/ClientProviderTests.cs |
Moves body assertions to baseline files. |
src/Providers/ScmMethodProviderCollection.cs |
Implements typed response deserialization. |
Review details
- Files reviewed: 36/37 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: jorgerangel-msft <[email protected]>
Jorge Rangel (jorgerangel-msft)
left a comment
There was a problem hiding this comment.
Copilot there's spelling errors we should address by simply changing the test to avoid the warning / error :
cspell --no-progress .
packages/http-client-csharp/generator/TestProjects/Local.Tests/ExtensibleEnumTests.cs:25:62 - Unknown word (FEFF)
There was a problem hiding this comment.
🟢 Approval recommended
The implementation is scoped, preserves documented compatibility behavior, and has representative generation and runtime coverage.
Review details
- Files reviewed: 38/39 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: jorgerangel-msft <[email protected]>
Fixed in 5c0d5d6 by adding a |
There was a problem hiding this comment.
🟡 Changes recommended
Plain-text routing breaks special response types and rejects relative URI values.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 59/60 changed files
- Comments generated: 2
- Review effort level: Balanced
…ive and enum types Co-authored-by: jorgerangel-msft <[email protected]>
There was a problem hiding this comment.
🔵 Needs a closer look
Plain-text URI responses still reject relative URI values.
Review details
Suppressed comments (1)
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs:943
new Uri(content)rejects relative URL values, while the established JSON and XML deserializers preserve them withUriKind.RelativeOrAbsolute(MrwSerializationTypeDefinition.cs:2454-2455,MrwSerializationTypeDefinition.Xml.cs:1068). Pass thatUriKindhere and update the plain-text URI baseline to cover a relative value; this also remains unresolved from the prior review thread.
Type t when t == typeof(Uri) => New.Instance(typeof(Uri), content),
- Files reviewed: 63/64 changed files
- Comments generated: 0 new
- Review effort level: Balanced
…arsing Co-authored-by: jorgerangel-msft <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Mixed JSON/plain-text string responses can fail when the server returns an unquoted plain-text body.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 63/64 changed files
- Comments generated: 1
- Review effort level: Balanced
…rsions Co-authored-by: jorgerangel-msft <[email protected]>
Co-authored-by: jorgerangel-msft <[email protected]>
There was a problem hiding this comment.
🟢 Approval recommended
The implementation removes reflection-based conversion while preserving nullable, BOM, plain-text, and special-case behavior with broad baseline coverage.
Review details
- Files reviewed: 63/64 changed files
- Comments generated: 0 new
- Review effort level: Balanced
|
|
||
| if (IsConvertibleFromBinaryData(responseBodyType) | ||
| && (responseBodyType.IsFrameworkType || responseBodyType.IsEnum) | ||
| && !responseBodyType.Equals(typeof(BinaryData)) |
There was a problem hiding this comment.
Copilot why do we need the responseBodyType.Equals(typeof(BinaryData)) check if we are already checked IsConvertibleFromBinaryData ?
There was a problem hiding this comment.
IsConvertibleFromBinaryData is a broad capability check (it intentionally returns true for BinaryData), but this specific branch builds JSON-document conversion scaffolding. Without !responseBodyType.Equals(typeof(BinaryData)), BinaryData responses would go through the JSON parse setup instead of preserving the raw payload path. So the extra check keeps BinaryData on its existing direct-content conversion path.
There was a problem hiding this comment.
🟡 Changes recommended
Nullable plain-text null responses regress when the body contains surrounding whitespace.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 63/64 changed files
- Comments generated: 1
- Review effort level: Balanced
| return responseBodyType.IsNullable | ||
| ? new TernaryConditionalExpression(content.Equal(Literal("null")), Null.CastTo(responseBodyType), deserializedValue) | ||
| : deserializedValue; |
Co-authored-by: jorgerangel-msft <[email protected]>
Co-authored-by: jorgerangel-msft <[email protected]>
There was a problem hiding this comment.
🟢 Approval recommended
The reflection-free conversions are localized, preserve documented compatibility cases, and have comprehensive generation and runtime coverage.
Review details
- Files reviewed: 63/64 changed files
- Comments generated: 0 new
- Review effort level: Balanced
JoshLove-msft
left a comment
There was a problem hiding this comment.
Found one new correctness issue in plain-text duration conversion; details inline. Existing review threads were not duplicated.
--generated by Copilot
| Type t when t == typeof(bool) => Static<bool>().Invoke(nameof(bool.Parse), content).As<bool>(), | ||
| Type t when t == typeof(Guid) => Static<Guid>().Invoke(nameof(Guid.Parse), content).As<Guid>(), | ||
| Type t when t == typeof(Uri) => New.Instance<Uri>(content, FrameworkEnumValue(UriKind.RelativeOrAbsolute)), | ||
| Type t when t == typeof(TimeSpan) => content.As<string>().ParseTimeSpan(Literal(SerializationFormat.Duration_Constant.ToFormatSpecifier() ?? throw new InvalidOperationException())), |
There was a problem hiding this comment.
[P2] Honor the duration's wire encoding in the plain-text parser. InputDurationType also maps to TimeSpan, so forcing "c" here makes a seconds-encoded response body 60 deserialize as 60 days instead of one minute, and makes the default ISO 8601 body PT1H throw (the duration encoding mappings are in generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs:449-474). Select parsing from the response encoding, retaining constant-format parsing for the existing plain-time/constant case, and add ISO 8601 and seconds/milliseconds response coverage.
--generated by Copilot
C# convenience methods deserialize primitive responses with
BinaryData.ToObjectFromJson<T>(), which relies on reflection and is not Native AOT-compatible.JsonElementreads for primitive and enum responses, including sync and async methods.TimeSpanformatting. Leave plain-text, raw binary, model, and collection handling unchanged.Generated
int32response conversion: