fix(csharp): make generichost oneOf constructors public
Description
Fixes #23046.
The C# Generic Host template previously used model mutability (x-model-is-mutable) to determine the visibility of oneOf constructors. However, mutability does not reliably indicate whether callers need to construct a model: an immutable oneOf wrapper may still be used as an API input.
This change adds the codegen vendor extension x-model-is-operation-input. It identifies models reachable from operation parameters or request bodies, including through:
- referenced and composed schemas (
oneOf,allOf, andanyOf) - object properties
- array items
- schema-valued
additionalProperties - parameter and request-body media-type content
Note: Read-only schema branches are excluded.
For a oneOf constructor, the template first checks x-model-is-operation-input:
- If the flag is present, the constructor uses the configured visibility:
publicby default orinternalwhennonPublicApi=true. - If the flag is absent, the constructor is always
internal.
Example
Given this OpenAPI document:
openapi: 3.0.3
info:
title: Upload API
version: 1.0.0
paths:
/upload:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/InitiateUploadRequest'
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseOnlyValue'
components:
schemas:
InitiateUploadRequest:
type: object
properties:
dynamicMetadata:
type: object
additionalProperties:
$ref: '#/components/schemas/DynamicMetadataValue'
DynamicMetadataValue:
oneOf:
- type: string
- type: number
ResponseOnlyValue:
oneOf:
- type: string
- type: integer
DynamicMetadataValue is reachable from the /upload request body through InitiateUploadRequest.dynamicMetadata.additionalProperties. Its constructors therefore use the configured visibility, which is public by default:
public DynamicMetadataValue(string value)
public DynamicMetadataValue(decimal value)
ResponseOnlyValue is referenced only by the response. It is not an operation input, so its constructors remain internal:
internal ResponseOnlyValue(string value)
internal ResponseOnlyValue(int value)
Compatibility note
Note that this change may alter the generated API surface for some oneOf models. Constructors that were previously public because the model was considered mutable will now be internal when the model is only used in responses or is not reachable from an operation input.
This is intentional, but consumers that manually construct response-only oneOf models may need to update their code.
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
(For Windows users, please run the script in WSL)./mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit
Commit all changed files.
This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
These must match the expectations made by your contribution.
You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example./bin/generate-samples.sh bin/configs/java*.
IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed. - If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.
@mandrean (2017/08) @shibayan (2020/02) @Blackclaws (2021/03) @lucamazzanti (2021/05) @iBicha (2023/07)
Summary by cubic
Make C# Generic Host oneOf model constructors public only for operation inputs (request bodies and parameters). Fixes #23046 so immutable oneOf inputs are constructible across assemblies by default, while non-input oneOf constructors remain internal.
- Bug Fixes
- Emit
{{>visibility}}for Generic HostoneOfconstructors and set topubliconly when the model is an operation input; otherwiseinternal. RespectsnonPublicApi=true. - Detect operation input models in the generator (
x-model-is-operation-input); updated template and codegen, added unit test and minimal OpenAPI fixture, and regenerated samples.
- Emit