Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Generate AOT-compatible C# primitive responses - #11931

Open
Jorge Rangel (jorgerangel-msft) with Copilot wants to merge 23 commits into
mainfrom
copilot/generate-aot-compatible-code
Open

Generate AOT-compatible C# primitive responses#11931
Jorge Rangel (jorgerangel-msft) with Copilot wants to merge 23 commits into
mainfrom
copilot/generate-aot-compatible-code

Conversation

Copilot AI commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

C# convenience methods deserialize primitive responses with BinaryData.ToObjectFromJson<T>(), which relies on reflection and is not Native AOT-compatible.

  • Deserialization: Replace reflection-based conversion with typed JsonElement reads for primitive and enum responses, including sync and async methods.
  • Compatibility: Preserve nullable values, UTF-8 BOM support, and TimeSpan formatting. Leave plain-text, raw binary, model, and collection handling unchanged.

Generated int32 response conversion:

using Stream stream = result.GetRawResponse().Content.ToStream();
using JsonDocument document = JsonDocument.Parse(stream);
return ClientResult.FromValue(document.RootElement.GetInt32(), result.GetRawResponse());

@azure-pipelines

Copy link
Copy Markdown
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.

Copilot AI linked an issue Sep 10, 2026 that may be closed by this pull request
@jorgerangel-msft Jorge Rangel (jorgerangel-msft) changed the title [WIP] Generate AOT compatible code for GetSandboxesCount operation [WIP] Generate AOT compatible code for operations that return a primitive as resp body Sep 10, 2026
@microsoft-github-policy-service microsoft-github-policy-service Bot added emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp labels Sep 10, 2026
Copilot AI changed the title [WIP] Generate AOT compatible code for operations that return a primitive as resp body Generate AOT-compatible C# primitive responses Sep 10, 2026
@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@11931

commit: 2c5ad78

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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 JsonElement reads for primitive and enum responses.
  • Preserves plain-text behavior and constant-format TimeSpan conversion.
  • 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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

Copilot AI commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Copilot there's spelling errors we should address by simply changing the test to avoid the warning / error :

Fixed in 5c0d5d6 by adding a // cspell:ignore FEFF comment at the top of the file. Verified npx cspell --no-progress now reports 0 issues for this file.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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 with UriKind.RelativeOrAbsolute (MrwSerializationTypeDefinition.cs:2454-2455, MrwSerializationTypeDefinition.Xml.cs:1068). Pass that UriKind here 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Copilot AI review requested due to automatic review settings September 11, 2026 22:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot why do we need the responseBodyType.Equals(typeof(BinaryData)) check if we are already checked IsConvertibleFromBinaryData ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment on lines +953 to +955
return responseBodyType.IsNullable
? new TernaryConditionalExpression(content.Equal(Literal("null")), Null.CastTo(responseBodyType), deserializedValue)
: deserializedValue;

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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 JoshLove-msft left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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())),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate AOT compatible code when an operation returns a primitive

4 participants