-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Throw unhandled exceptions during prerendering #8616
Conversation
@@ -17,18 +19,17 @@ public class ComponentRenderingFunctionalTests : IClassFixture<MvcTestFixture<Ba | |||
public ComponentRenderingFunctionalTests(MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting> fixture) | |||
{ | |||
Factory = fixture; | |||
Client = Client ?? CreateClient(fixture); |
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.
The paradigm used in these tests was broken now that we report errors. The FetchData component is part of all of these tests, and when used with prerendering it was throwing an exception because the service configuration wasn't correct.
I can't help feeling like this is all more complicated than necessary. Using httpclient to call your own API isn't something we'd normally tell users to do.
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 can simply do Client ?? CreateClient(fixture.WithWebHostBuilder(b => b.ConfigureServices(s => s.AddRazorComponents()))
or extend the MVC fixture and configure it there. Both work. I usually do the WithWebHostBuilder because I'm cheap and I don't bother with inheritance, but this is something you can do a nested class of the test and that's totally fine.
protected override async Task OnInitAsync() | ||
{ | ||
await base.OnInitAsync(); | ||
throw new InvalidTimeZoneException("test"); |
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.
One of my favourites for testing, I've never seen this in the wild.
@@ -0,0 +1,10 @@ | |||
@page "/components/throws" | |||
|
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.
Note that I didn't include a test for the case where a component throws during construction/DI/parameters. That results in #8190
I already have tests and a fix for this on the components relayering PR, btw |
31da0de
to
cb146ab
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.
Looks solid
7780b9e
to
767e368
Compare
1def9b7
to
862daf0
Compare
@SteveSandersonMS - could you take a second look at this? I have more that I want to follow up on but I will do that in a separate PR. |
@@ -11,74 +11,263 @@ namespace Microsoft.AspNetCore.Components | |||
/// </summary> | |||
public static class EventCallbackFactoryBinderExtensions | |||
{ | |||
private delegate bool BindConverter<T>(object obj, out T value); |
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 reworked all of this logic to avoid throwing exceptions where possible. Now that we're handling the exceptions here it just makes sense to avoid the noise of throwing them in the first place. Now all of this code is tryparse where possible.
return null; | ||
}; | ||
value = converted; | ||
return true; |
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.
The difference between nullable and non-nullable:
- Nullable treats empty string as
null
and will bind successfully - non-nullable fails to parse empty string, and will retain the previous value.
It's problematic to convert an empty value to default
for non-nullable. It will check the value of the text field to 0
instead of ""
.
862daf0
to
ca14bc7
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.
Looks extra-solid now! I'm glad we're finally filling in some of the details of these scenarios.
Fixes: #8609 Currently exceptions thrown during prerendering are simply logged. This change uses the existing *unhandled exception* mechanism of the renderer/circuit to throw these. The result is that the developer exception page just works for prerendering.
ca14bc7
to
6fdde36
Compare
@@ -26,8 +28,12 @@ public async Task<IEnumerable<string>> PrerenderComponentAsync(ComponentPrerende | |||
GetFullUri(context.Request), | |||
GetFullBaseUri(context.Request)); | |||
|
|||
// We don't need to unsubscribe because the circuit host object is scoped to this call. | |||
circuitHost.UnhandledException += CircuitHost_UnhandledException; |
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.
On second look, I don't think this is correct. The circuit will live longer than the request and when the signalr connection gets stablished you don't want to have this handler throwing.
If you take a look at how i'm doing this on my PR
https://github.com/aspnet/AspNetCore/pull/7954/files#diff-d33c04a2c673816a9a5c6e959a8e5270R91
I'm specifically basing it on whether I'm prerrendering or not.
You can keep this if you want to, but I'm gonna have to change it on my PR so it just adds work to me :(
I'll leave it up to yo.
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 don't understand this, or how to do extra work to support something that isn't implemented yet, so I'm going to go ahead and merge this 😆
Fixes: #8609
Currently exceptions thrown during prerendering are simply logged. This
change uses the existing unhandled exception mechanism of the
renderer/circuit to throw these. The result is that the developer
exception page just works for prerendering.