Is there an existing issue for this?
Describe the bug
When the server runs into an unhandled exception, the client's circuit is forcefully closed by the client via a message sent to the client. However, the onCircuitClosed function of the CircuitHandler handles attached with the Blazor.start() options is not triggered in this case. From what I can tell, there is no actual way to get informed that the circuit was forcefully closed in this way via code (other than maybe observing style changes to the error UI element).
Cause
Unhandled server-side exceptions are handled by notifying the client via a custom event (JS.Error) which then closes the connection from the client side.
Event is handled here:
|
connection.on('JS.Error', error => { |
|
this._renderingFailed = true; |
|
this.unhandledError(error); |
|
showErrorNotification(); |
|
}); |
Which calls unhandledError():
|
private unhandledError(err: Error): void { |
|
this._logger.log(LogLevel.Error, err); |
|
|
|
// Disconnect on errors. |
|
// Trying to call methods on the connection after its been closed will throw. |
|
this.disconnect(); |
|
} |
Expected Behavior
The onCircuitClosed function is invoked, informing all handles that the circuit was closed. Ideally I would even like to have the close reason as argument (enum? or the error object/message) so the client can react to these cases (e.g., by reloading the page). The CircuitHandler interface could also be extended with something like an onCircuitFaulted function.
Steps To Reproduce
Server Setup
TestPage.razor:
@page "/test"
@implements IDisposable
<a href="/">Home</a>
@code {
public void Dispose() => throw new Exception();
}
_Host.cshtml:
<!-- ... -->
<body>
<!-- ... -->
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({
circuitHandlers: [{
onCircuitOpened: () => console.log('circuit opened'),
onCircuitClosed: () => console.log('circuit closed')
}]
});
</script>
</body>
</html>
Procedure
Navigate to /test and then press the Home link.
Result
The onCircuitClosed function is never invoked and the console message is not printed. The Page gets stuck in its last render state before the circuit was closed. However, the error UI element with the ID blazor-error-ui will receive the appropriate style changes (style set to display:block).
Notes
The component does not have to be a page (just for demonstration), also works with normal components that are disposed at some point. Also works with Exceptions thrown inside IAsyncDisposable implementations. In theory, all unhandled exceptions will cause this issue. The reason for why I selected the dispose pattern as source for the exception is because not even an ErrorBoundary component will catch those exceptions and because I had some occurrences where async disposing of JS module references failed and caused the circuit to fault. While I understand that the later can be circumvented via a try-catch block, I still need a way to automatically reloading the page in case of errors since in my case, the client is in a stand-alone kiosk-mode and I cannot rely on a user clicking the reload button in the error UI.
Exceptions (if any)
No response
.NET Version
8.0.202
Anything else?
No response
Is there an existing issue for this?
Describe the bug
When the server runs into an unhandled exception, the client's circuit is forcefully closed by the client via a message sent to the client. However, the
onCircuitClosedfunction of theCircuitHandlerhandles attached with theBlazor.start()options is not triggered in this case. From what I can tell, there is no actual way to get informed that the circuit was forcefully closed in this way via code (other than maybe observing style changes to the error UI element).Cause
Unhandled server-side exceptions are handled by notifying the client via a custom event (
JS.Error) which then closes the connection from the client side.Event is handled here:
aspnetcore/src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts
Lines 166 to 170 in 63c8031
Which calls
unhandledError():aspnetcore/src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts
Lines 292 to 298 in 63c8031
Expected Behavior
The
onCircuitClosedfunction is invoked, informing all handles that the circuit was closed. Ideally I would even like to have the close reason as argument (enum? or the error object/message) so the client can react to these cases (e.g., by reloading the page). TheCircuitHandlerinterface could also be extended with something like anonCircuitFaultedfunction.Steps To Reproduce
Server Setup
TestPage.razor:_Host.cshtml:Procedure
Navigate to
/testand then press theHomelink.Result
The
onCircuitClosedfunction is never invoked and the console message is not printed. The Page gets stuck in its last render state before the circuit was closed. However, the error UI element with the IDblazor-error-uiwill receive the appropriate style changes (styleset todisplay:block).Notes
The component does not have to be a page (just for demonstration), also works with normal components that are disposed at some point. Also works with Exceptions thrown inside
IAsyncDisposableimplementations. In theory, all unhandled exceptions will cause this issue. The reason for why I selected the dispose pattern as source for the exception is because not even anErrorBoundarycomponent will catch those exceptions and because I had some occurrences where async disposing of JS module references failed and caused the circuit to fault. While I understand that the later can be circumvented via atry-catchblock, I still need a way to automatically reloading the page in case of errors since in my case, the client is in a stand-alone kiosk-mode and I cannot rely on a user clicking the reload button in the error UI.Exceptions (if any)
No response
.NET Version
8.0.202
Anything else?
No response