Skip to content

Guard exploded string-struct query parameters against null ToString in C# emitter - #11439

Open
jorgerangel-msft with Copilot wants to merge 7 commits into
mainfrom
copilot/bugfix-null-tostring-serialization
Open

Guard exploded string-struct query parameters against null ToString in C# emitter#11439
jorgerangel-msft with Copilot wants to merge 7 commits into
mainfrom
copilot/bugfix-null-tostring-serialization

Conversation

Copilot AI commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Exploded @query array/dictionary parameters backed by a string struct (extensible string enum) generated code that passed .ToString() directly to AppendQuery(..., escape: true). A default-constructed value has a null internal string, so .ToString() returns null and Uri.EscapeDataString throws ArgumentNullException at runtime.

Changes

  • Null/empty guard on exploded elements (RestClientProvider.BuildAppendQueryStatement): wraps each AppendQuery in if (!string.IsNullOrEmpty(...)) for array and dictionary explode when the element/value is a string-backed extensible enum. Gated by a new IsExtensibleStringEnum helper (IsEnum && IsStruct && UnderlyingEnumType == typeof(string)) so int/float/double enums and plain values are unaffected.
  • Dictionary explode value fix: the enum was serialized from the KeyValuePair (item) rather than item.Value, yielding wrong output (e.g. @param.ToSerialString(), ((int)@param)). Now uses item.Value, correcting the p6/p7 paths as well.
  • Tests: extended TestBuildCreateRequestMethodWithQueryParameters with extensible string enum array + dictionary parameters; baseline updated.

Generated output now:

foreach (var @param in include)
{
    if (!string.IsNullOrEmpty(@param.ToString()))
    {
        uri.AppendQuery("include[]", @param.ToString(), true);
    }
}

@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.

… emitter

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Jul 29, 2026
Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix null ToString() guard in C# emitter for string structs Guard exploded string-struct query parameters against null ToString in C# emitter Jul 29, 2026
Copilot AI requested a review from jorgerangel-msft July 29, 2026 15:31
@pkg-pr-new

pkg-pr-new Bot commented Jul 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: f473482

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.

Pull request overview

This PR fixes a runtime crash and a serialization bug in the C# HTTP client emitter when generating exploded query parameters for string-backed extensible enums (struct enums). It ensures null/empty enum string values aren’t passed into AppendQuery(..., escape: true) and corrects dictionary explode serialization to use KeyValuePair.Value rather than the KeyValuePair itself.

Changes:

  • Add string.IsNullOrEmpty(...) guards around per-element/per-value AppendQuery calls for exploded arrays/dictionaries when the element type is a string-backed extensible enum.
  • Fix dictionary explode enum serialization to serialize item.Value (not the KeyValuePair), correcting generated output for both string and numeric enum dictionary values.
  • Extend RestClientProviderTests.TestBuildCreateRequestMethodWithQueryParameters and update the expected baseline to cover extensible string enum exploded array/dictionary cases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs Guards exploded query serialization for extensible string enums and fixes dictionary explode value serialization.
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs Adds new test inputs for extensible string enum exploded array/dictionary query parameters.
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/TestBuildCreateRequestMethodWithQueryParameters.cs Updates expected generated output to include null/empty guards and corrected dictionary value serialization.

…explode query params

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
…y and shared helper

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
…ble enum query param test

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
Copilot AI requested a review from jorgerangel-msft July 29, 2026 17:04
…l guard validation

Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com>
if (IsExtensibleStringEnum(elementType))
{
forEachStatement.Add(Declare("paramStr", typeof(string), convertedItem, out VariableExpression cachedVar));
forEachStatement.Add(new IfStatement(Not(StringSnippets.IsNullOrEmpty(cachedVar.As<string>())))

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.

This guard also filters out an explicitly constructed empty-string enum value, not just the default struct's null backing value. The generated extensible-enum constructor rejects null but accepts "", and AppendQuery(..., "", true) safely represents that value as an empty query entry; after this change an array/dictionary element created from "" is silently omitted instead. Could this check only for null and add coverage for an empty-string enum element/value?

--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.

[Bug]: C# emitter does not guard against null ToString() when serializing exploded query parameters backed by string structs

4 participants