Skip to content

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

Merged
merged 13 commits into from
Feb 13, 2019
Merged

Improve Components error handling #7165

merged 13 commits into from
Feb 13, 2019

Conversation

pranavkm
Copy link
Contributor

  • 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

Fixes #4964

@Eilon Eilon added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Jan 31, 2019
@pranavkm pranavkm force-pushed the prkrishn/error-reporting branch from 73a5c87 to 2910504 Compare February 4, 2019 19:49
@pranavkm
Copy link
Contributor Author

pranavkm commented Feb 4, 2019

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.

@SteveSandersonMS
Copy link
Member

@pranavkm OK, sounds good. Please let us know when this is ready for a final review.

@pranavkm pranavkm force-pushed the prkrishn/error-reporting branch from 2910504 to 3768419 Compare February 9, 2019 01:43
@pranavkm
Copy link
Contributor Author

pranavkm commented Feb 9, 2019

🆙 📅

@javiercn javiercn self-assigned this Feb 11, 2019
// 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());
Copy link
Member

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

Copy link
Contributor Author

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 AggregateExceptions - 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)

@jkotalik jkotalik removed their request for review February 11, 2019 14:59
Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking solid to me.

@javiercn Could you give sign-off before @pranavkm merges? I know you've had some pretty detailed involvement in the final changes here.

@pranavkm pranavkm force-pushed the prkrishn/error-reporting branch from bfb0f57 to f1b6f16 Compare February 13, 2019 14:31
@@ -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();
Copy link
Contributor Author

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.

Copy link
Contributor Author

@pranavkm pranavkm left a 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)
Copy link
Contributor Author

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
@pranavkm pranavkm force-pushed the prkrishn/error-reporting branch from f1b6f16 to bfb3386 Compare February 13, 2019 20:01
@pranavkm
Copy link
Contributor Author

🆙 📅

Copy link
Member

@javiercn javiercn left a 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>
Copy link
Member

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

Copy link
Contributor Author

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?

Copy link
Member

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

@pranavkm pranavkm merged commit cddbc2e into master Feb 13, 2019
@pranavkm pranavkm deleted the prkrishn/error-reporting branch February 13, 2019 22:22
@pranavkm
Copy link
Contributor Author

Thanks for looking through the PR!

@chucker
Copy link

chucker commented Feb 19, 2019

Hi,

I saw someone struggle with a dependency injection error in an RC project, where adding an @inject statement to their component caused a blank page to render. No error was logged to the browser console or the VS output window.

Will this PR improve this behavior, or should I file a separate issue?

@pranavkm
Copy link
Contributor Author

pranavkm commented Feb 19, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants