Skip to content

[csharp][restsharp][httpclient] Keep every accepted content type in the Accept header - #25247

Merged
wing328 merged 2 commits into
OpenAPITools:masterfrom
MrD4rkne:fix/csharp-restsharp-select-header-accept
Oct 14, 2026
Merged

wing328 merged 2 commits into
OpenAPITools:masterfrom
MrD4rkne:fix/csharp-restsharp-select-header-accept

Conversation

@MrD4rkne

@MrD4rkne MrD4rkne commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

ClientUtils.SelectHeaderAccept sends only application/json whenever it is one of the operation's response types, dropping every other type. For an operation whose success response is non-JSON (e.g. application/octet-stream) and which uses JSON only for errors, the client then sends an Accept header the server cannot satisfy on the success path.

The header now lists all accepted types, with JSON types listed first. Operations that declare only application/json, or no JSON type, produce the same header as before.

  • Scope: restsharp, httpclient and unityWebRequest, which share csharp/ClientUtils.mustache; their samples are regenerated. generichost and csharp-functions have their own copy of SelectHeaderAccept and are left for a follow-up.
  • Behaviour change: order in Accept carries no preference (RFC 9110 §12.5.1), so a server that applies its own preference among equal-q types may now return a non-JSON response for operations that also declare XML or another type, where JSON was forced before. ASP.NET Core and Spring keep the listed order and still return JSON. To force the old header, set it in the InterceptRequest hook, since Configuration.DefaultHeaders is overwritten by the operation's Accept.
  • Added the Java test CSharpClientCodegenTest#testSelectHeaderAcceptKeepsAllTypesJsonFirst.
  • Added AcceptHeaderTests to the restsharp net4.7/MultipleFrameworks sample: a local HTTP stub checks that PetApi.GetPetById (xml + json) sends application/json,application/xml. On master it sends application/json and the test fails:
  Expected: application/json,application/xml
  Actual:   application/json

Fixes #9737

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    Commit all changed files.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

cc @mandrean @shibayan @Blackclaws @lucamazzanti


Summary by cubic

Fixes SelectHeaderAccept in the C# client so the Accept header keeps every response type the operation declares instead of collapsing to application/json whenever JSON is among them. JSON types are listed first; operations that declare only JSON, or no JSON, produce the same header as before.

  • A server may now return a non-JSON response where JSON was forced before, since Accept order carries no preference (RFC 9110 §12.5.1). Set Accept: application/json per request to keep the old behavior.
  • Applies to restsharp, httpclient, and unityWebRequest, which share csharp/ClientUtils.mustache; samples are regenerated and new tests cover mixed JSON/XML responses.

Written for commit 89c85ac. Summary will update on new commits.

View guided diff

MrD4rkne and others added 2 commits October 13, 2026 14:19
…he Accept header

SelectHeaderAccept collapsed the Accept header to "application/json" whenever
JSON was among the candidates, dropping the operation's other response types.
Operations whose primary response is binary (or any non-JSON type) and only
use JSON for error responses then advertise an Accept the server cannot
honour for the success path.

Send all accepted types, JSON ones first so servers that honour Accept order
still answer with the body the JSON codec can parse.

Co-authored-by: CLIN <CLIN@foss.dk>
…sample

An operation that produces both XML and JSON must send both types, JSON
first. Fails against the previous SelectHeaderAccept, which sent only
application/json.

Co-authored-by: CLIN <CLIN@foss.dk>
@MrD4rkne
MrD4rkne marked this pull request as ready for review October 13, 2026 13:39

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 26 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java:432">
P2: These assertions verify sorting but not that every accepted type is returned; `SelectHeaderAccept` could still discard non-JSON types and pass. Assert the full `string.Join` expression.</violation>
</file>

Reply to a comment to ask cubic a question or push back. It learns from your replies.

View guided diff | Re-trigger cubic

File clientUtils = files
.get(Paths.get(output.getAbsolutePath(), "src", "Org.OpenAPITools", "Client", "ClientUtils.cs").toString());
assertNotNull(clientUtils);
assertFileContains(clientUtils.toPath(), "accepts.OrderBy(accept => IsJsonMime(accept) ? 0 : 1)");

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: These assertions verify sorting but not that every accepted type is returned; SelectHeaderAccept could still discard non-JSON types and pass. Assert the full string.Join expression.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java, line 432:

<comment>These assertions verify sorting but not that every accepted type is returned; `SelectHeaderAccept` could still discard non-JSON types and pass. Assert the full `string.Join` expression.</comment>

<file context>
@@ -409,6 +409,30 @@ public void testUserAgentIsNotUrlEncoded() throws IOException {
+        File clientUtils = files
+                .get(Paths.get(output.getAbsolutePath(), "src", "Org.OpenAPITools", "Client", "ClientUtils.cs").toString());
+        assertNotNull(clientUtils);
+        assertFileContains(clientUtils.toPath(), "accepts.OrderBy(accept => IsJsonMime(accept) ? 0 : 1)");
+        assertFileNotContains(clientUtils.toPath(), "return \"application/json\";");
+    }
</file context>

@wing328 wing328 added this to the 7.27.0 milestone Oct 14, 2026
@wing328
wing328 merged commit 782ef0b into OpenAPITools:master Oct 14, 2026
75 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [csharp] [netcore] Default Accept Headers do not respect 2xx vs non-2xx response code differences

2 participants