Add DispatchExceptionAsync to ComponentBase#46074
Conversation
|
I've been playing with Selenium/E2E testing for a few days and this appears to be the cleanest way to test this scenario if I'm understanding it correctly |
| } | ||
| } | ||
|
|
||
| private Task ThrowExceptionAsync() |
There was a problem hiding this comment.
This is not throwing the exception asynchronously. The thread is not yielded at any point, so this is similar/equivalent to the SyncExceptionDispatch case.
For the exception to be thrown asynchronously you need to use something like await Task.Yield() before throwing the exception.
Also, I will point out that we normally also write unit tests for these types of behavior in the Renderer itself. There we normally use a TaskCompletionSource to very accurately control the process.
There was a problem hiding this comment.
Good point.
In fact more generally I think these test cases are missing the key scenario: when an exception happens outside the normal lifecycle flow and you couldn't just do a normal throw anyway. With the way SyncExceptionDispatch and AsyncExceptionDispatch are structured, DispatchExceptionAsync is no different from simply using throw at that point, because we're still within the task chain of the lifecycle method.
It would be good to cover the primary use case where this new feature is what causes the exception to be associated with the renderer. For example, by using Task.Run to simulate having some code running completely separately from the renderer callstack/task chain:
void ExternalExceptionDispatch()
{
Task.Run(() =>
{
// Inside Task.Run, we're outside the call stack or task chain of the lifecycle method, so
// DispatchExceptionAsync is needed to get an exception back into the component
_ = DispatchExceptionAsync(new InvalidTimeZoneException());
});
}If we are going to have the SyncExceptionDispatch/AsyncExceptionDispatch cases, I imagine they would be there to cover the case where people are calling DispatchExceptionAsync even though they didn't need to (i.e., calls that are already on the lifecycle method call stack), so they could be simplified to just dispatching a newed-up exception like:
async Task SyncExceptionDispatch()
{
await DispatchExceptionAsync(new InvalidTimeZoneException("Sync"));
}
async Task AsyncExceptionDispatch()
{
await Task.Yield();
await DispatchExceptionAsync(new InvalidTimeZoneException("Async"));
}Co-authored-by: Steve Sanderson <SteveSandersonMS@users.noreply.github.com>
|
@SteveSandersonMS @javiercn I should have test(s) for the new, correct testing scenario that you guys described completed soon. |
I totally understand that it's nonobvious, but For more general context, |
Add DispatchExceptionAsync to ComponentBase
Adds way for developers to dispatch exceptions outside of the Blazor sync context to the renderer.
Description
DispatchExceptionAsyncsends exceptions from theComponentBaseto theRenderervia theRenderHandle. See below proposal for more info.Fixes #44920
API Proposal: #46068