[Validation] C# unions across JavaScript interop
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
**Scenario contact:** @oroztocil
## Scenario
An app exchanges C# union values with JavaScript in both directions: as arguments to JavaScript calls, as values returned from JavaScript, and as parameters and return values of methods JavaScript calls back into .NET. This validates that a union serializes as its active case, comes back as the right case, and fails understandably when the incoming JSON matches no case.
## Minimum build
.NET 11 Preview 7 or later.
## Configurations to cover
* Blazor Web App
* [ ] Static SSR
* [x] Interactive Server
* [x] Interactive WebAssembly
* [ ] Interactive Auto
* [x] Standalone WebAssembly
* [ ] Hybrid (MAUI)
## Also exercise
* [x] Published output
* [ ] An existing .NET 10 app upgraded to .NET 11
* [x] Trimming or ahead-of-time compilation
* [ ] More than one server instance, or a proxy in front
* [ ] Hot Reload
* [ ] An IDE as well as the command line
* [ ] Container
## Setup
Union types are a preview language feature, so each project needs `preview`.
## What to build
An app with a small JavaScript module and a page that exercises interop in both directions. Define an unambiguous union such as `(int, string)`, a nullable union such as `(int?, string)`, and a union of two records whose JSON shapes are hard to tell apart. Pass each of them to JavaScript, return each of them from JavaScript, and add a method JavaScript can invoke that both accepts and returns a union. Show the results in the page, and watch what actually crosses the boundary in the browser console.
## Things to try
* A union whose active case is null.
* A union nested inside a larger object rather than passed on its own.
* JavaScript returning a shape that matches no declared case, or that matches more than one.
* The two-record union with and without a `[JsonUnion]` classifier.
## Expected behavior
Only the active case crosses the boundary, it comes back as the same case, and anything JavaScript sends that does not fit is reported rather than guessed at.
### Must hold
* An integer case arrives in JavaScript as a number, a string case as a string, and a record case as that record's own object, with no wrapper object around the active case.
* A value returned from JavaScript becomes the same case it was sent as, including when the active case is null.
* A union passed to and returned from a method JavaScript invokes on .NET round-trips as the same case.
* JSON matching no declared case produces an error naming the problem rather than a default value.
* The ambiguous record union either resolves through its classifier or fails with a message naming the ambiguity.
### Expected differences between configurations
No user-observable differences are expected between the covered configurations.
## Evidence to capture
The actual JSON that crossed the boundary for each union case, taken from the browser console or the network log, rather than a description of it.
## Documentation to use
* [C# union types, .NET 11 release notes](https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-11#c-union-types)
* [Union types, C# language reference](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/union)
* [Call JavaScript from .NET](https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-11.0)
* [Call .NET from JavaScript](https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-11.0)
## What to report
Report results using the format described in the [validation testing manual](https://github.com/dotnet/aspnetcore/issues/68479). Include link to a repository with the test app.
Contributor guide
Assessment
This issue has not been assessed yet.