-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Improve Components error handling #7165
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
Conversation
src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs
Outdated
Show resolved
Hide resolved
src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs
Outdated
Show resolved
Hide resolved
src/Components/Server/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
Outdated
Show resolved
Hide resolved
73a5c87
to
2910504
Compare
I addressed changes to the sources, but I'm going to hold off on test changes (which currently don't compile) until we resolve https://github.com/aspnet/AspNetCore/pull/7240/files. There's a @javiercn's PR sets up the tests correctly, and I would need to rebase my changes on top of it to make the correct assertions. |
@pranavkm OK, sounds good. Please let us know when this is ready for a final review. |
2910504
to
3768419
Compare
🆙 📅 |
src/Components/Blazor/Blazor/src/Rendering/WebAssemblyRenderer.cs
Outdated
Show resolved
Hide resolved
// waiting for it to throw later. This can happen if the task is produced by | ||
// an 'async' state machine (the ones generated using async/await) where even | ||
// the synchronous exceptions will get captured and converted into a faulted | ||
// task. | ||
ExceptionDispatchInfo.Capture(task.Exception.InnerException).Throw(); | ||
HandleException(task.Exception.GetBaseException()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain to me the difference between these two? I thought you had to do ExceptionDispatchInfo.Capture to preserve the original callstack
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right ExceptionDispatchInfo.Capture(...).Throw()
is useful when you want to rethrow preserving the stack trace. In the regular case, HandleException
logs the error so we don't need to wrap it up here. HtmlRenderer
continues re-throwing and consequently uses ExceptionDispatchInfo
. AggregateException.GetBaseException
unwraps nested instances of AggregateException
s - https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/AggregateException.cs#L290-L303. In the most common case where there's exactly one InnerException
this should return that value. If the AggregateException
was produced by many failing tasks, we should still be able to observe all of them rather than the first (viz task.Exception.InnerException
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bfb0f57
to
f1b6f16
Compare
@@ -329,8 +272,7 @@ public virtual Task InvokeAsync(Func<Task> workItem) | |||
// This is for example when we run on a system with a single thread, like WebAssembly. | |||
if (_dispatcher == null) | |||
{ | |||
workItem(); | |||
return Task.CompletedTask; | |||
return workItem(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@javiercn noticed a blazor test fail and this turned out to be the culprit. workItem()
returns a Task
and we weren't awaiting it as part of InvokeAsync
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆙 📅
@@ -482,15 +428,45 @@ private void ProcessRenderQueue() | |||
} | |||
} | |||
|
|||
private void InvokeRenderCompletedCalls(ArrayRange<RenderTreeDiff> updatedComponents) | |||
private Task InvokeRenderCompletedCalls(ArrayRange<RenderTreeDiff> updatedComponents) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this from async void
to Task
returning which we ignore. This follows the same pattern we would tell users to do, plus avoids any state machine if everything is synchronous.
* Change event handlers IHandleEvent, IHandleAfterEvent to be async. * Return faulted tasks to Renderer instead of handling exceptions in ComponentBase * Use ILogger in RemoteRenderer, and log to console in WebAssemblyRenderer * Cleaning up touched files Fixes #4964
f1b6f16
to
bfb3386
Compare
🆙 📅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great improvement!
@@ -11,6 +13,7 @@ public interface IHandleAfterRender | |||
/// <summary> | |||
/// Notifies the component that it has been rendered. | |||
/// </summary> | |||
void OnAfterRender(); | |||
/// <returns>A <see cref="Task"/> that represents the asynchronous event handling operation.</returns> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a bad copy-paste
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't think of anything else to say here so went with the boiler plate. Suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
asynchronous event handling operation
-> asynchronous rendering operation
Thanks for looking through the PR! |
Hi, I saw someone struggle with a dependency injection error in an RC project, where adding an Will this PR improve this behavior, or should I file a separate issue? |
A new issue with steps to reproduce the error would be great. That said, this change just went in, so I'd wait for preview3 before filing one. |
Fixes #4964