-
Notifications
You must be signed in to change notification settings - Fork 10.3k
[Components] Adds support for rendering async components #6708
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
javiercn
commented
Jan 15, 2019
- Converts SetParameters to SetParametersAsync
- Captures all the returned task produced by SetParametersAsync of each component to properly await them.
- Introduces RenderRootComponentAsync to render the root component and deterministically wait for all async work to be done.
- Protects the state in Renderer from concurrent modifications.
src/Components/src/Microsoft.AspNetCore.Components/IComponent.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/CascadingValue.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/ComponentBase.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/Rendering/ComponentState.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/Rendering/HtmlRenderer.cs
Outdated
Show resolved
Hide resolved
Could this fix the following issue? #5592 (comment) |
Question I forgot to ask elsewhere, how will this handle encoding? |
@rynowak The HTML renderer gets a Func<string,string> encoder that does the encoding. Due to the fact that this lives in Microsoft.AspNetCore.Components and we don't want to bring a dependency to the webencoders in that package. Mvc just provides the htmlEncoder resolved from DI |
src/Components/src/Microsoft.AspNetCore.Components/ParameterCollection.cs
Outdated
Show resolved
Hide resolved
Ok cool beans |
d2577cd
to
a67f314
Compare
src/Components/src/Microsoft.AspNetCore.Components/Rendering/ComponentState.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/CascadingValue.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/ComponentBase.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/IComponent.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/ParameterCollection.cs
Outdated
Show resolved
Hide resolved
src/Components/src/Microsoft.AspNetCore.Components/Rendering/Renderer.cs
Outdated
Show resolved
Hide resolved
@@ -22,6 +23,14 @@ public abstract class Renderer : IDisposable | |||
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it | |||
private bool _isBatchInProgress; | |||
private int _lastEventHandlerId = 0; | |||
private List<Task> _pendingTasks = new List<Task>(); |
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 might be missing something, but it looks like in the non-HtmlRenderer case, this list will grow infinitely and is never cleared after the initial render.
Should we do something so that only HtmlRenderer actually populates this list, and the others do nothing in AddToPendingTasks
? The AddToPendingTasks
could be changed to a virtual method that no-ops in the default case.
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 gets cleaned up in all code paths as
void RenderRootComponent(int componentId, ParameterCollection initialParameters)
{
ReportAsyncExceptions(RenderRootComponentAsync(componentId, initialParameters));
}
Internally makes sure that all the cleanup happens.
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 thought that only happened on the first render cycle. When some event like a button click happens later in the other renderers, this code path doesn't execute, does it?
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.
Ah, I see what you mean. You're right. But it has an easy fix
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 null the list after RenderRootComponentAsync is done
src/Components/src/Microsoft.AspNetCore.Components/Rendering/Renderer.cs
Outdated
Show resolved
Hide resolved
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.
Looking great! Hopefully the remaining points won't be hugely disruptive to resolve. Thanks for tracking down so many fine details about the lifecycle method execution process.
Updated |
// reason we have OnAfterRenderAsync is so that the developer doesn't | ||
// have to use "async void" and do their own exception handling in | ||
// the case where they want to start an async task. | ||
var taskWithHandledException = HandleAfterRenderException(onAfterRenderTask); |
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 like we don't need the taskWithHandledException
var, or do we?
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 compiler complains if we take it out
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.
_ = HandleAfterRenderException(...);
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.
Excellent!
* Updates the IComponent interface to rename Init into Configure * Updates the IComponent interface to change SetParameters for SetParametersAsync and make it return a Task that represents when the component is done applying the parameters and potentially triggering one or more renders. * Updates ComponentBase SetParametersAsync to ensure that OnInit(Async) runs before OnParametersSet(Async). * Introduces ParameterCollection.FromDictionary to generate a parameter collection from a dictionary of key value pairs. * Introduces RenderComponentAsync on HtmlRenderer to support prerrendering of async components. * Introduces RenderRootComponentAsync on the renderer to allow for asynchronous prerrendering of the root component.
e2c8696
to
e7892e1
Compare
This is blocked waiting on this unrelated failing test: @natemcmaster Is there something we can do here? I've triggered several builds already |
d2bf15b
to
e7892e1
Compare
If the flaky test is blocking you, log an issue and mark it as skipped. |
Merging in as this is blocked on an unrelated test. |