-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API for dispatching to renderer sync context and capturing exceptions #44920
Comments
Previous incarnation of this request: #27716 |
@SteveSandersonMS Would it work if we had a I am not 100% sure how the |
No conversion. I was just proposing some way to run code (which may be async, but not value-returning) within the context of a component. The reason for returning Your more constrained proposal of
Yeah, pretty sure it would end up being some function on |
Thanks for contacting us. We're moving this issue to the |
@javiercn @SteveSandersonMS while looking into this I think it makes sense to have this in EDIT: There isn't correct access for |
Sounds about right.
It looks like we could add an internal void HandleComponentException(Exception exception, int componentId)
=> HandleExceptionViaErrorBoundary(exception, GetRequiredComponentState(componentId)); ... and call that from the |
This sounds reasonable. We might want to put the functionality in the RenderHandle (which internally delegates to the renderer) and expose a helper method on ComponentBase to let people easily raise them. |
Using @SteveSandersonMS's internal method, I get this code block in public void Dispatch (Action workItem)
{
if (_renderer == null)
{
ThrowNotInitialized();
}
try
{
Dispatcher.InvokeAsync(workItem);
}
catch (Exception e)
{
_renderer.HandleComponentException(e, _componentId);
}
} Am I understanding the ask correctly? |
Close! A few other details:
Maybe something like: public void Dispatch(Func<Task> workItem)
{
_ = Dispatcher.InvokeAsync(async () =>
{
try
{
await workItem();
}
catch (Exception e)
{
_renderer.HandleComponentException(e, _componentId);
}
});
} Some drawbacks with this whole design:
An alternative design that's clearer about what's going on, even at the cost of requiring more code to use it in some common cases, would be not having public Task DispatchExceptionAsync(Exception exception)
{
return Dispatcher.InvokeAsync(() => _renderer.HandleComponentException(e, _componentId));
} This is now purely responsible for getting the exception into the renderer, so it's now up to the developer to combine this with // Some code in a component
try
{
await InvokeAsync(async () => { /* some code that may throw, possibly asynchronously */ });
}
catch (Exception e)
{
await DispatchExceptionAsync(e);
} Now they can get back results from What do you think? |
For sure, I think that similar to how I'm torn but think the second approach may be better since the result still comes back. Is there a way you're leaning with this? |
Yes, I would lean towards the second ( |
Hmm, this lambda expression throws CS1673. Do you know a workaround to this? |
@Nick-Stanton copy the _renderer into a local variable. |
Currently if you have an exception that occurs off the Blazor sync context, there isn't a good way to marshal it onto the sync context. In our internal code we've sometimes do a weird trick of performing a fake render that throws.
We should have some new API that's like
InvokeAsync
but instead of returning aTask
, it returnsvoid
and handles any errors by dispatching them to the renderer. Maybe it could be calledDispatch
or similar.Note that it somehow needs to execute in the context of a particular component, so the error can hit the right error boundary. Ideally it would not be possible to pretend to be some other component - maybe it should rely on having access to a particular component's
RenderHandle
.The text was updated successfully, but these errors were encountered: