Skip to content

fix(http-server-csharp): emitter type errors - #11749

Open
sophia-ramsey wants to merge 12 commits into
mainfrom
sramsey/csharp-emitter-fixes
Open

fix(http-server-csharp): emitter type errors#11749
sophia-ramsey wants to merge 12 commits into
mainfrom
sramsey/csharp-emitter-fixes

Conversation

@sophia-ramsey

Copy link
Copy Markdown
Member

Addresses errors I encountered while using the C# server emitter to emit code from the ai foundry spec for the agent contracts api service package. Includes tests

Issues addressed:

  • duplicate nullable suffixes: fixed optional nullable value parameters emitting invalid C# types by ensuring nullable suffixes are applied only once (int?? to int?)
  • multipart content: fixed multipart operations emitting <Unresolved Symbol ...> by falling back to the original @multipartBody metadata when canonicalization data is unavailable
  • record parameter fixes: fixed error-model constructors emitting incompatible types such as Record, Array, or object instead of the same concrete structured types used by their properties
  • parameter ordering fix: fixed controller calls passing positional arguments in a different order than their business-interface signatures while preserving positional syntax for existing generated code
  • void as a success type: fixed void | @error responses generating invalid result assignments by excluding error branches from success-response analysis and emitting direct awaits with NoContent()
  • optional nullables for errors: errors with optional properties would emit with those properties non-optional and only show as optional if the spec specified | null
  • fix model only emitter option: output-type:models was emitting controllers and responses, and it now emits models only
  • namespace issue: the emitter was generating code with the wrong namespace, using whichever namespace was the first to appear in the typespec (ex. using the namespace of a package that was imported) instead of the intended namespace

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-server-csharp
Show changes

@typespec/http-server-csharp - fix ✏️

fix optional error properties, output-type:models, and incorrect namespace issue

@typespec/http-server-csharp - fix ✏️

fix errors in emitter including duplicate nullable suffixes, unresolved symbols for multipart content, incompatible types, parameter ordering, and void as a success type

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-server-csharp@11749

commit: cde3acf

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 several correctness issues in the @typespec/http-server-csharp emitter that surfaced when generating controllers/models from a larger real-world spec (nullable handling, multipart fallback behavior, error model ctor typing, operation canonicalization/service namespace resolution, controller call argument ordering, and models-only output). It also updates snapshots and adds targeted tests to prevent regressions.

Changes:

  • Fixes nullable emission across models, interfaces, mocks, controllers, and error constructors (including avoiding invalid T??).
  • Improves service discovery/namespace selection and introduces an operation-source map to better align controller generation with business/interface operations.
  • Adds/updates tests and snapshots for models-only output, multipart fallback behavior, and controller/action response analysis.

Reviewed changes

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

Show a summary per file
File Description
packages/http-server-csharp/test/snapshots/sample-service/generated/models/PetListResult.cs Snapshot update: nullable reference type for optional nextLink.
packages/http-server-csharp/test/snapshots/sample-service/generated/models/Pet.cs Snapshot update: nullable reference types for optional properties.
packages/http-server-csharp/test/snapshots/sample-service/generated/controllers/PetsController.cs Snapshot update: DELETE returns 204 NoContent without assigning void result.
packages/http-server-csharp/test/nullable-parameters.test.ts New regression test ensuring optional nullable value params don’t emit T??.
packages/http-server-csharp/test/generation.test.ts Updates expectations for nullable reference types and error ctor optional nullables.
packages/http-server-csharp/test/emitter.test.ts Adds test verifying output-type=models emits only models/support files.
packages/http-server-csharp/src/utils/namespace-utils.ts Removes findServiceNamespace (service resolution moved to service-discovery).
packages/http-server-csharp/src/service-resolution.ts Adds options to skip canonicalization; tracks canonical op → source operation map; uses declared service namespace.
packages/http-server-csharp/src/service-resolution.test.ts Adds tests for declared service namespace precedence, operation source tracking, and canonicalization skipping.
packages/http-server-csharp/src/service-discovery.ts Introduces getServiceNamespace and uses compiler helper for full namespace name.
packages/http-server-csharp/src/emitter.tsx Implements models-only emission path; wires operation source context; avoids emitting mocks/project/docs in models-only mode.
packages/http-server-csharp/src/context/operation-source-context.ts New context for canonical operation → source operation mapping.
packages/http-server-csharp/src/components/type-expression/type-expression.tsx Adds helper for detecting nullable value-type unions; uses it in union type rendering.
packages/http-server-csharp/src/components/scaffolding/mock-implementations.tsx Multipart fallback without canonical metadata; fixes nullable value union parameter emission in mocks.
packages/http-server-csharp/src/components/render-root.tsx Detects multipart based on decorators when canonicalization is unavailable.
packages/http-server-csharp/src/components/multipart-fallback.test.tsx New test ensuring multipart interfaces/mocks stay aligned without canonical metadata.
packages/http-server-csharp/src/components/models/models.tsx Adjusts nullable semantics for properties; improves JsonNodes detection for inherited error models.
packages/http-server-csharp/src/components/models/model-helpers.ts Enhances JsonNodes detection to recurse into tuples/arrays/records and optionally include inheritance.
packages/http-server-csharp/src/components/models/error-models.tsx Uses TypeExpression for structured ctor param types; fixes optional/nullability behavior in error ctors.
packages/http-server-csharp/src/components/models/error-models.test.tsx New tests for structured ctor parameter typing and inherited JsonObject using.
packages/http-server-csharp/src/components/interfaces/interfaces.tsx Multipart fallback via decorators; fixes optional nullable value union parameters (avoids T??).
packages/http-server-csharp/src/components/interfaces/interfaces.test.tsx New tests for nullable suffix correctness and multipart fallback behavior.
packages/http-server-csharp/src/components/controllers/controllers.tsx Passes operation source into ControllerAction to improve call-site alignment.
packages/http-server-csharp/src/components/controllers/controllers.test.tsx Adds controller ordering test using operation source context.
packages/http-server-csharp/src/components/controller-action/response-analysis.ts Excludes error branches from success-response analysis; returns 204 when success is void.
packages/http-server-csharp/src/components/controller-action/controller-action.tsx Reorders call args to match business/interface signature; updates ProducesResponseType/body handling for void unions.
packages/http-server-csharp/src/components/controller-action/controller-action.test.tsx Adds tests for void-success unions, preserving value-success behavior, and argument ordering for request/protocol params.
.chronus/changes/sramsey-csharp-server-nullable-2026-7-12-14-45-16.md Changelog entry for the emitter fixes.
Suppressed comments (3)

packages/http-server-csharp/src/components/controller-action/controller-action.tsx:61

  • Controller action parameters can still emit int?? for value?: int32 | null because TypeExpression returns int? and optional: true adds another ?. Passing the inner value type to TypeExpression (only when the parameter is optional and the union is a nullable value union) avoids the duplicate suffix.
        type: <TypeExpression type={p.property.sourceType.type} />,

packages/http-server-csharp/src/components/controller-action/controller-action.tsx:72

  • Same T?? risk exists for optional nullable value unions on query/header parameters; TypeExpression emits T? for T | null and the optional flag adds another ?. Apply the same inner-type substitution here to keep controller method signatures valid.
        type: <TypeExpression type={p.property.sourceType.type} />,

packages/http-server-csharp/src/components/controllers/controllers.test.tsx:142

  • The expected controller implementation calls GetPetAsync(feature, petId, apiVersion), but the expected interface signature just above is GetPetAsync(string petId, string feature, string apiVersion). This would not compile as generated code; the argument order in the expected output should match the interface signature.
            var result = await PetStoreImpl.GetPetAsync(feature, petId, apiVersion);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

import * as cs from "@alloy-js/csharp";
import { Attribute } from "@alloy-js/csharp";
import { isErrorModel, isVoidType } from "@typespec/compiler";
import { isErrorModel, isVoidType, type Operation } from "@typespec/compiler";
Comment on lines 121 to 125
function findServiceNs(ns: TspNamespace): TspNamespace | undefined {
for (const child of ns.namespaces.values()) {
if (isStdNamespace(child)) continue;
// If this namespace has content (models, interfaces, operations, enums), use it
// Otherwise, recurse deeper
const hasContent =
child.models.size > 0 ||

expect(
<Wrapper>
<OperationSources.Provider value={new Map([[canonOp, businessGetPet]])}>
Copilot AI review requested due to automatic review settings August 24, 2026 17:50
@azure-sdk-automation

azure-sdk-automation Bot commented Aug 24, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

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 26 out of 29 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

packages/http-server-csharp/src/components/controller-action/controller-action.tsx:173

  • responseStatusCode for [ProducesResponseType] is currently derived only from hasBody, but the method body can return Accepted(...) when statusCode === 202 (and StatusCode(statusCode, ...) for other non-200 codes). This can cause the emitted attribute to advertise OK/NoContent even when the action returns 201/202, which makes the generated metadata inaccurate.
  // Determine the success status code from the response
  const { statusCode, hasBody } = getSuccessStatusCode($.program, props.operation);

  // Determine response type for ProducesResponseType attribute
  const returnType = props.operation.sourceType.returnType;
  const responseStatusCode = hasBody ? "OK" : "NoContent";
  let responseTypeExpr: Children | undefined = undefined;

@sophia-ramsey sophia-ramsey changed the title Sramsey/csharp emitter fixes fix(http-server-csharp): emitter type errors Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants