Fix JSInterop DefaultAsyncTimeout swallow issue#67013
Conversation
|
Thanks for your PR, @GOVINSAGA. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
Hmm, not sure how I feel about this one. This now means that if a JS interop call timed out, ComponentBase will throw instead of no-op, which might result in the session terminating (the circuit getting disposed). Changing the exception is not a breaking change in the strict sense but its still a behavior breaking change. Anyone that used to do try
{
}
catch (OperationCanceledException ex)
{
}will now have to update to That said, reading through #21384 (comment) (might want to include this on the description here next time) I think it's ok. I would suggest that for completeness we set the InnerException to the TCS, as that makes it easier to distinguish against another JSException cause. |
Fixes #21384.
Root Cause: When
DefaultAsyncTimeoutfires, theCancellationTokenSourcetriggerstcs.TrySetCanceled(), producing a task withIsCanceled = true.ComponentBasethen swallows it in its catch blocks (since it ignores canceled tasks to handle normal component disposal).My approach: Modify only the
InvokeAsyncoverload that creates theDefaultAsyncTimeoutCTS. Wrap the inner call in a try/catch that catchesOperationCanceledExceptiononly whencts.IsCancellationRequestedis true, and re-throws as aJSException.Why this avoids the previous issues:
InvokeAsync(CancellationToken)overload is untouchedComponentBasewon't swallow it —JSExceptionproduces a faulted task (IsCanceled = false)ComponentBase.cs