Skip to content

[http-client-csharp] Serialize enum options-bag properties when protocol flattens them to string - #11488

Merged
JoshLove-msft merged 2 commits into
microsoft:mainfrom
m-nash:fix/optionsbag-enum-conversion
Jul 30, 2026
Merged

[http-client-csharp] Serialize enum options-bag properties when protocol flattens them to string#11488
JoshLove-msft merged 2 commits into
microsoft:mainfrom
m-nash:fix/optionsbag-enum-conversion

Conversation

@m-nash

@m-nash m-nash commented Jul 30, 2026

Copy link
Copy Markdown
Member

Problem

When an @@override groups operation parameters into an options-bag model, the generated convenience method delegates to the protocol method by reading each argument off the options model (options.Foo). If an options property is an enum/union but the protocol method flattens that parameter to its serialized form (e.g. string), the delegation passed the enum value directly where a string is expected — so the generated code does not compile.

The non-grouped convenience path already handles this: for an enum convenience parameter it emits convenienceParam.Type.ToSerial(...) (e.g. foo?.ToString()). The grouped path — which resolves arguments through MethodParameterSegments (introduced in #11238) — built a raw property-access expression and skipped that conversion.

Before

// options.Resampling is an (extensible) enum; the protocol method takes a string
return this.GetPoint(collectionId, options.Resampling, cancellationToken.ToRequestOptions());

After

return this.GetPoint(collectionId, options.Resampling?.ToString(), cancellationToken.ToRequestOptions());

Fix

  • ModelProviderSnippets.GetPropertyExpression gains an overload that also returns the leaf PropertyProvider, so callers can inspect the resolved property's type.
  • ScmMethodProviderCollection.GetProtocolMethodArguments serializes the leaf in the grouped path when it is an enum and the protocol parameter is not — applying a null-conditional first when the property is nullable — mirroring the non-grouped path's ToSerial behavior. Non-enum properties are unchanged.

Tests

  • New MethodParameterSegments_EnumGroupedQueryParam_SerializesToProtocol (validated against a TestData expected file) — reproduces the missing conversion without the fix, passes with it.
  • Full Microsoft.TypeSpec.Generator.ClientModel (1539) and Microsoft.TypeSpec.Generator (1781) suites pass.

…col flattens them to string

When an `@@override` groups parameters into an options-bag model, the generated
convenience method delegates to the protocol method by reading each argument off
the options model (`options.Foo`). If an options property is an enum/union but the
protocol method flattens that parameter to its serialized form (e.g. `string`),
the delegation passed the enum directly, producing code that does not compile.

The non-grouped convenience path already serializes enums via
`convenienceParam.Type.ToSerial(...)`. The grouped (MethodParameterSegments) path
built a raw property-access expression and skipped that conversion.

`ModelProviderSnippets.GetPropertyExpression` now optionally returns the leaf
`PropertyProvider`, and `GetProtocolMethodArguments` serializes the leaf when it is
an enum and the protocol parameter is not (applying a null-conditional first when
the property is nullable), mirroring the non-grouped path. The generated body now
emits e.g. `options.Resampling?.ToString()`.

Added `MethodParameterSegments_EnumGroupedQueryParam_SerializesToProtocol`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b564000b-729c-4371-b5c4-8ce14462cee9
@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 30, 2026
@m-nash
m-nash requested a review from Copilot July 30, 2026 17:32
@pkg-pr-new

pkg-pr-new Bot commented Jul 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 52ed3ff

@github-actions

Copy link
Copy Markdown
Contributor

No changes needing a change description found.

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

Fixes a C# http-client-csharp generator compilation issue where options-bag convenience methods could forward an enum-typed options property directly into a protocol parameter that had been flattened to its serialized primitive type (e.g., string), by applying the same enum-to-serial conversion used in the non-grouped path.

Changes:

  • Add a ModelProviderSnippets.GetPropertyExpression overload that also returns the resolved leaf PropertyProvider for type inspection.
  • Update grouped-parameter forwarding (ScmMethodProviderCollection.GetProtocolMethodArguments) to serialize enum leaf properties when the protocol parameter is non-enum, including ?. handling for nullable enums.
  • Add a regression test + expected output fixture covering enum options-bag forwarding to a flattened protocol string parameter.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Snippets/ModelProviderSnippets.cs Adds a GetPropertyExpression overload returning the leaf PropertyProvider so callers can apply type-based conversions.
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs Serializes grouped options-bag enum leaf properties when protocol parameters are flattened to non-enum types.
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs Adds a regression test asserting enum-to-string serialization occurs for grouped query params.
packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MethodParameterSegments_EnumGroupedQueryParam_SerializesToProtocol.cs Expected method-body output fixture validating the emitted forwarding expression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b564000b-729c-4371-b5c4-8ce14462cee9

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

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

Comments suppressed due to low confidence (1)

packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs:930

  • When serializing an enum options-bag property for a flattened protocol parameter, the null-conditional is only applied when the leaf property type is nullable. For nested segment paths (MethodParameterSegments.Count > 2), GetPropertyExpression will emit a null-conditional during navigation (e.g. options.Inner?.Resampling), which makes the overall expression nullable even if the leaf enum is non-nullable. Without adding a null-conditional here, the generated code becomes options.Inner?.Resampling.ToString(), which calls Nullable<T>.ToString() and produces an empty string when Inner is null instead of forwarding null (and may incorrectly send a query value).
                            if (leafProperty.Type.IsNullable)
                            {
                                propertyExpression = propertyExpression.NullConditional();
                            }
                            propertyExpression = leafProperty.Type.ToSerial(propertyExpression);

@JoshLove-msft
JoshLove-msft enabled auto-merge July 30, 2026 18:13
@JoshLove-msft
JoshLove-msft added this pull request to the merge queue Jul 30, 2026
Merged via the queue into microsoft:main with commit ead9d14 Jul 30, 2026
29 checks passed
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.

3 participants