More granular JSExceptions for JSInterop
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Is there an existing issue for this?
- [X] I have searched the existing issues
### Is your feature request related to a problem? Please describe the problem.
The invocation can fail for multiple reasons when using JSInterop to call JavaScript functions from Blazor. Currently, the erroring case is handled on the JS side, where a boolean indicating whether the invocation was successful together with the error message, and the stack (stack trace) is returned to the C# side as we can see [here](https://github.com/dotnet/aspnetcore/blob/main/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts#L401-L430) and the formatting function [here](https://github.com/dotnet/aspnetcore/blob/main/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts#L540-L546). On the C# side a `JSException` is constructed containing the message and nothing else. But what we are missing is the type of error. An error can basically be one of these types with the APIs available in the browser:
- EvalError
- RangeError
- ReferenceError
- SyntaxError
- TypeError
- URIError
Apart from these, we also have some standard exceptions called the DOMExceptions. There are many different kinds of DOMExceptions as well that are defined in [the WebIDL standard specifications](https://webidl.spec.whatwg.org/#idl-DOMException-error-names). They differ only by having different names and then of cause by being used in different scenarios.
Many JS methods can throw different error types depending on how the invocation failed. As developers, we would like to know why an invocation failed, but we only have the `JSException` with a raw string message in it. People have employed different methods to parse the string to recover the original reason that the invocation failed. But nowhere in the message is the actual `name` of the error, as we don't capture that when formatting the error. Instead, people try to find consistent parts of the error message and check if the error contains this subpart to identify the type. An example could be to check if the phrase "is aborted" is in the message to identify it as an AbortError DOMException.
### Describe the solution you'd like
I would like it if Blazor would send back the `name` attribute that is defined on all error types so that developers can check for this property to identify the reason why an invocation failed without doing any guesswork.
Additionally, it would be awesome if there were exception types for all standard JS error names so that developers could catch specific reasons for failure like this:
```csharp
try
{
var result = await JSRuntime.InvokeAsync("navigator.clipboard.readText");
}
catch (NotAllowedJSException exception)
{
Logger.LogWarning(exception, "The user has not given permission to read the clipboard.");
}
catch (NotFoundJSException exception)
{
Logger.LogWarning(exception, "There wasn't text in the clipboard.");
}
catch (JSException exception)
{
Logger.LogError(exception, $"An JS error with name '{exception.Name}' happened.");
}
catch (Exception exception)
{
Logger.LogError(exception, $"Some other unexpected error happened '{exception.GetType().Name}': \"{exception.Message}\"");
}
```
### Additional context
I previously made the following article that also repeats some of my above points but with more details:
https://kristoffer-strube.dk/post/typed-exceptions-for-jsinterop-in-blazor/
In the article I also started on this library which is a workaround to get typed exception types: https://github.com/KristofferStrube/Blazor.WebIDL
Contributor guide
Assessment
This issue has not been assessed yet.