[Validation] Analyzer diagnostics for JavaScript interop
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
**Scenario contact:** @ilonatommy
## Scenario
JavaScript interop is one of the easiest places in Blazor to write code that compiles cleanly and then fails at runtime: calling into JavaScript before the browser is there, returning a value the app cannot deserialize, or exposing a .NET method to JavaScript that JavaScript is unable to reach. This validates that the build now points these problems out while the code is being written, that the guidance is correct, and that it stays quiet for interop code that is written properly.
## Minimum build
.NET 11 Preview 7 or later.
## Configurations to cover
* Blazor Web App
* [x] Static SSR
* [x] Interactive Server
* [ ] Interactive WebAssembly
* [ ] Interactive Auto
* [ ] Standalone WebAssembly
* [ ] Hybrid (MAUI)
These diagnostics are produced by the compiler, so they do not vary by render mode. The configuration below is the one needed to reproduce the runtime behavior the warning predicts, not a matrix to work through. Static SSR is included because prerendering is what makes the `BL0016` runtime failure reproducible.
## Also exercise
* [ ] Published output
* [ ] An existing .NET 10 app upgraded to .NET 11
* [ ] Trimming or ahead-of-time compilation
* [ ] More than one server instance, or a proxy in front
* [ ] Hot Reload
* [x] An IDE as well as the command line
* [ ] Container
## Setup
Work in an IDE as well as at the command line. Part of what is being tested is whether the guidance appears while typing and whether the offered fixes apply cleanly.
The three diagnostics this scenario covers are:
| Id | Title | Code fix |
|---|---|---|
| `BL0010` | Use `InvokeVoidAsync` instead of `InvokeAsync` | No |
| `BL0015` | `[JSInvokable]` methods should be public | Yes |
| `BL0016` | Unguarded JS interop call | Yes |
## What to build
An app with a component that talks to JavaScript in several ways, written first the way a developer might do it without thinking too hard. Call a JavaScript function that returns nothing, but ask for a result anyway. Expose a .NET method to JavaScript for a callback, and declare it without making it reachable. Call into JavaScript from a lifecycle method that also runs while the page is being prerendered, without protecting against the call failing. Alongside these, write the same kinds of interop correctly as well, so you can see whether the build stays quiet about code that is already right. Write some of this in a component file and some in a plain class, since both are ordinary places for interop code to live.
## Things to try
* Building at the command line and reading the messages that appear.
* Opening the same code in an IDE and comparing what is shown there.
* Applying the offered automatic fixes for `BL0015` and `BL0016`, and rebuilding.
* Applying a fix to a method that already has several modifiers on it, and to one written in a component file rather than a plain class.
* Running the app afterwards to confirm the corrected interop actually works.
* Writing interop that is already correct in a few different shapes to see whether any of them are flagged unnecessarily.
* Deliberately keeping one problem in place and running the app, to see the runtime failure the guidance was warning about. The report behind `BL0016` names three contexts where interop can fail: prerendering, Interactive Server when the circuit has dropped, and a WebView. Prerendering is the easiest to reproduce here; if you have a Hybrid app to hand, try it there too.
* Building the same code in the server project, in the `.Client` project, and in a Razor Class Library, confirming the warnings appear in all three. The analyzer reaches these through different routes, one bundled in the SDK and one flowing through the `Microsoft.AspNetCore.Components` package.
## Expected behavior
Each mistake is reported at build time with advice that is correct, and correct interop is left alone.
### Must hold
* Each deliberately wrong piece of interop produces a build warning carrying the expected identifier from the table above, at the correct line.
* The same warnings appear both at the command line and in the IDE, with the same identifiers and counts.
* The same warnings appear whether the code is built in the server project, the `.Client` project, or a Razor Class Library.
* Applying the `BL0015` and `BL0016` code fixes produces code that compiles, keeps the surrounding modifiers and formatting intact, and works when the app runs.
* The correctly written interop produces none of these warnings.
* Running the app with one problem left in place reproduces the runtime failure the message described.
### Expected differences between configurations
* The warnings themselves are identical everywhere, because they are produced at compile time.
* Only the runtime failure behind `BL0016` differs: it needs a configuration that renders on the server before the browser takes over, which is why static SSR is covered here.
## Documentation to use
* [InvokeVoidAsync analyzer release notes](https://learn.microsoft.com/aspnet/core/release-notes/aspnetcore-11#invokevoidasync-analyzer)
* [Call JavaScript functions from .NET methods](https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-11.0)
* [Call .NET methods from JavaScript functions](https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-11.0)
* [Prerendering with JavaScript interop](https://learn.microsoft.com/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-11.0#javascript-interop-calls-without-a-circuit)
## 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.