Skip to content
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

Merged
merged 1 commit into from
Mar 20, 2019

Conversation

rynowak
Copy link
Member

@rynowak rynowak commented Mar 18, 2019

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.

@rynowak rynowak requested a review from javiercn March 18, 2019 03:17
@@ -17,18 +19,17 @@ public class ComponentRenderingFunctionalTests : IClassFixture<MvcTestFixture<Ba
public ComponentRenderingFunctionalTests(MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting> fixture)
{
Factory = fixture;
Client = Client ?? CreateClient(fixture);
Copy link
Member Author

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.

Copy link
Member

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");
Copy link
Member Author

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"

Copy link
Member Author

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

@javiercn
Copy link
Member

I already have tests and a fix for this on the components relayering PR, btw

@rynowak rynowak force-pushed the rynowak/prerendering branch from 31da0de to cb146ab Compare March 18, 2019 15:03
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.

Looks solid

@rynowak rynowak force-pushed the rynowak/prerendering-error-throwing branch 2 times, most recently from 7780b9e to 767e368 Compare March 18, 2019 17:19
@rynowak rynowak changed the base branch from rynowak/prerendering to master March 18, 2019 17:19
@Eilon Eilon added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Mar 18, 2019
@rynowak rynowak force-pushed the rynowak/prerendering-error-throwing branch 2 times, most recently from 1def9b7 to 862daf0 Compare March 19, 2019 18:48
@rynowak
Copy link
Member Author

rynowak commented Mar 19, 2019

@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);
Copy link
Member Author

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;
Copy link
Member Author

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 "".

@rynowak rynowak force-pushed the rynowak/prerendering-error-throwing branch from 862daf0 to ca14bc7 Compare March 19, 2019 21:34
@SteveSandersonMS SteveSandersonMS self-requested a review March 20, 2019 00:12
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.

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.
@rynowak rynowak force-pushed the rynowak/prerendering-error-throwing branch from ca14bc7 to 6fdde36 Compare March 20, 2019 15:00
@@ -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;
Copy link
Member

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.

Copy link
Member Author

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 😆

@rynowak rynowak merged commit b743ba2 into master Mar 20, 2019
@rynowak rynowak deleted the rynowak/prerendering-error-throwing branch March 20, 2019 20:02
halter73 pushed a commit to dotnet-maestro-bot/AspNetCore that referenced this pull request Mar 28, 2019
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.

4 participants