Retire standalone C# unions article; document where unions aren't supported#37276
Retire standalone C# unions article; document where unions aren't supported#37276danroth27 wants to merge 5 commits into
Conversation
Addresses #37275 (retire fundamentals/unions.md and integrate per-area) and #37274 (Blazor-specific notes in the relevant Blazor articles). C# unions are a language feature whose ASP.NET Core surface is small and flows through existing serialization-driven features. A standalone article under Fundamentals overstates the concept and forces readers to leave the article they were already in. This change: * Deletes aspnetcore/fundamentals/unions.md and removes its TOC entry. * Adds a redirect to fundamentals/minimal-apis/responses (the most common starting point for union usage). * Adds one short, moniker-gated (>= aspnetcore-11.0) note in each of: - fundamentals/minimal-apis/responses.md - web-api/action-return-types.md - signalr/hubs.md (JsonHubProtocol only) - fundamentals/openapi/aspnetcore-openapi.md (anyOf schema) - blazor/components/index.md (union component parameters + Razor literal-attribute workaround, tracked at dotnet/razor#13188) - blazor/components/dynamiccomponent.md (boxing rule) - blazor/state-management/prerendered-state-persistence.md (JsonSerializerContext doesn't flow into the unions deserializer) Each note links to the System.Text.Json unions article for the serialization behavior (case selection, classifiers, ambiguity) that's independent of ASP.NET Core. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@danroth27, I know this is still in draft, but just a note to save you time: I can clean the moniker versioning /build issues for all articles in the PR, once you feel like the updates are otherwise how you want them. I'll fix in review. What is happening: This is conflicting with the new sections that are dropped within that moniker block that are specifying: Usually we would create a new copy of the article that is for >= 11 going forward, which allows us to avoid any nested versioning speghetti and give a clear article dedicated to a version that can be archived or retired later. |
Follows reviewer feedback: assume STJ rules apply wherever JSON serialization is used. Don't repeat union behavior in every JSON surface; only call out the cases where unions are unsupported but a reader might expect them to work. Reverted: * fundamentals/minimal-apis/responses.md * web-api/action-return-types.md * fundamentals/openapi/aspnetcore-openapi.md * blazor/state-management/prerendered-state-persistence.md * The Toast example in blazor/components/index.md * The SaveOutcome example in signalr/hubs.md Kept / restructured (all moniker-gated >= aspnetcore-11.0): * blazor/components/index.md: Razor string-literal shortcut doesn't apply to union-typed parameters; relocated next to the existing string-literal documentation. * blazor/components/dynamiccomponent.md: DynamicComponent boxing rule for union parameters; slimmed to a NOTE block. * signalr/hubs.md: slimmed to a NOTE that MessagePack and Newtonsoft.Json hub protocols don't support unions. Added explicit not-supported notes: * fundamentals/minimal-apis/includes/parameter-binding8-10.md: unions are supported only as body (JSON); not in route/query/header/form. Links dotnet/aspnetcore#66648. * mvc/models/model-binding.md: same callout for [FromBody] vs other binding sources. Links dotnet/aspnetcore#66648. * blazor/fundamentals/navigation.md: [SupplyParameterFromQuery] and [SupplyParameterFromForm] don't support unions. Links #66648. Redirect updated to point at fundamentals/minimal-apis/parameter-binding (where the most relevant ASP.NET Core-specific not-supported note lives). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#66648 links Follow-up to reviewer feedback: * Drop the redirect entry. The unions.md article only ever shipped in preview docs, so no production redirect target is needed. * Revert blazor/components/dynamiccomponent.md. The DynamicComponent boxing behavior follows normal C# rules and produces a useful runtime error message; union-typed parameters won't be common enough to warrant a dedicated note. * Revert ms.date on fundamentals/minimal-apis/parameter-binding.md (only the include file changed; parent prose is unchanged). * Remove dotnet/aspnetcore#66648 references from the three non-body binding notes. Future support isn't certain enough to advertise. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Blazor route parameters parse route segments as strings without JSON parsing, so a [Parameter] typed as a C# union can't be populated from a route segment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@DeagleGross The existing article does a great job highlighting the new feature and where it applies. I think this kind of content would work better as a blog post on devblogs.microsoft.com/dotnet timed to .NET 11 instead of as a standalone doc. I'm happy to work with you to get that published. |
* signalr/hubs.md: close the outer >= aspnetcore-8.0 moniker block around the new >= aspnetcore-11.0 insert so the inner block parses correctly. Fixes 'No moniker-end found for >= aspnetcore-11.0' warning. * release-notes/aspnetcore-11/includes/csharp-unions-preview-6.md: rewrite to match the PR principles. Drops the broken xref to the deleted unions.md, links to the C# language reference and STJ docs instead of duplicating STJ behavior, and points readers to the in-context not-supported notes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
||
| :::moniker range=">= aspnetcore-11.0" | ||
|
|
||
| The string-literal shortcut applies only to parameters declared as `string`. A parameter declared as a [C# union type](/dotnet/csharp/whats-new/csharp-14#union-types) — even one whose cases include `string` — isn't a `string`-typed parameter, so the attribute value must be a C# expression. Use the `@` prefix, for example `Message="@("Saved.")"`, tracked at [dotnet/razor#13188](https://github.com/dotnet/razor/issues/13188). |
There was a problem hiding this comment.
| The string-literal shortcut applies only to parameters declared as `string`. A parameter declared as a [C# union type](/dotnet/csharp/whats-new/csharp-14#union-types) — even one whose cases include `string` — isn't a `string`-typed parameter, so the attribute value must be a C# expression. Use the `@` prefix, for example `Message="@("Saved.")"`, tracked at [dotnet/razor#13188](https://github.com/dotnet/razor/issues/13188). | |
| The string-literal shortcut applies only to parameters declared as `string`. A parameter declared as a [C# union type](/dotnet/csharp/whats-new/csharp-14#union-types), even one whose cases include `string`, isn't a `string`-typed parameter, so the attribute value must be a C# expression. Use the `@` prefix, for example `Message="@("Saved.")"`. This requirement is tracked at [dotnet/razor#13188](https://github.com/dotnet/razor/issues/13188). |
Very minor: Split to two sentances to make this a little more readable.
There was a problem hiding this comment.
If for updates at .NET 11, lead the paragraph with this ...
<!-- UPDATE 11.0 - Remove the following paragraph per resolution of the PU issue -->... and for the link convention, use this format ...
- [dotnet/razor#13188](https://github.com/dotnet/razor/issues/13188)
+ [Razor: extend literal-attribute shortcut to component parameters typed as a C# union with a string case (`dotnet/razor` #13188)](https://github.com/dotnet/razor/issues/13188)Here's a full suggestion for these, including Wade's suggestions. The issue is about making a change to the framework to address this, so I changed "requirement" to our 'for more info' lead-in ...
| The string-literal shortcut applies only to parameters declared as `string`. A parameter declared as a [C# union type](/dotnet/csharp/whats-new/csharp-14#union-types) — even one whose cases include `string` — isn't a `string`-typed parameter, so the attribute value must be a C# expression. Use the `@` prefix, for example `Message="@("Saved.")"`, tracked at [dotnet/razor#13188](https://github.com/dotnet/razor/issues/13188). | |
| <!-- UPDATE 11.0 - Remove the following paragraph per resolution of the PU issue --> | |
| The string-literal shortcut applies only to parameters declared as `string`. A parameter declared as a [C# union type](/dotnet/csharp/whats-new/csharp-14#union-types), even one whose cases include `string`, isn't a `string`-typed parameter, so the attribute value must be a C# expression. Use the `@` prefix, for example `Message="@("Saved.")"`. For more information, see [Razor: extend literal-attribute shortcut to component parameters typed as a C# union with a string case (`dotnet/razor` #13188)](https://github.com/dotnet/razor/issues/13188). |
|
|
||
| For more information, see [Use C# union types in ASP.NET Core](xref:fundamentals/unions). | ||
| <!-- TODO: System.Text.Json union APIs (JsonUnionAttribute, JsonTypeClassifier) are new in .NET 11; update to <xref:> once published to dotnet-api-docs. --> | ||
| Unions aren't supported for non-body binding sources such as route values, query strings, headers, and form fields. No newline at end of file |
There was a problem hiding this comment.
| Unions aren't supported for non-body binding sources such as route values, query strings, headers, and form fields. | |
| Union types aren't supported for non-body binding sources such as route values, query strings, headers, and form fields. |
Very minor. Consistant full term use of "Union types" for clarity.
wadepickett
left a comment
There was a problem hiding this comment.
@danroth27, PR Approved. Looks great! Inline I noted a couple very minor items you could take or leave.
There was a problem hiding this comment.
Hello from PTO! 👋😄
Per the style manual, there should be no spaces around em dashes ...
https://learn.microsoft.com/style-guide/punctuation/dashes-hyphens/
I placed the suggestions to update them.
| :::moniker range=">= aspnetcore-11.0" | ||
|
|
||
| > [!NOTE] | ||
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only as the body (as JSON). Non-body sources — route values, query string, headers, and form values — bind string values without JSON parsing, so they can't dispatch to a union case. |
There was a problem hiding this comment.
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only as the body (as JSON). Non-body sources — route values, query string, headers, and form values — bind string values without JSON parsing, so they can't dispatch to a union case. | |
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only as the body (as JSON). Non-body sources—route values, query string, headers, and form values—bind string values without JSON parsing, so they can't dispatch to a union case. |
| :::moniker range=">= aspnetcore-11.0" | ||
|
|
||
| > [!NOTE] | ||
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only with `[FromBody]`. The other binding sources — `[FromQuery]`, `[FromRoute]`, `[FromForm]`, and `[FromHeader]` — bind string values without JSON parsing, so they can't dispatch to a union case. |
There was a problem hiding this comment.
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only with `[FromBody]`. The other binding sources — `[FromQuery]`, `[FromRoute]`, `[FromForm]`, and `[FromHeader]` — bind string values without JSON parsing, so they can't dispatch to a union case. | |
| > [C# union types](/dotnet/csharp/whats-new/csharp-14#union-types) are supported only with `[FromBody]`. The other binding sources—`[FromQuery]`, `[FromRoute]`, `[FromForm]`, and `[FromHeader]`—bind string values without JSON parsing, so they can't dispatch to a union case. |
Closes #37275. Addresses #37274.
Deletes
aspnetcore/fundamentals/unions.mdand its TOC entry. No redirect — the article only shipped in preview docs.Principles
Changes
Adds short, moniker-gated (
>= aspnetcore-11.0) notes covering where C# unions aren't supported in ASP.NET Core but a reader might expect them to be:fundamentals/minimal-apis/includes/parameter-binding8-10.mdmvc/models/model-binding.md[FromQuery]/[FromRoute]/[FromForm]/[FromHeader]([FromBody]only)signalr/hubs.mdJsonHubProtocolonly)blazor/fundamentals/navigation.md[SupplyParameterFromQuery]and[SupplyParameterFromForm]blazor/fundamentals/routing.md@pageroute parametersblazor/components/index.mdNet change: -275 lines.
Verification
Verified against .NET 11 Preview 6:
Internal previews