[Blazor] Prevents HtmlRenderer from calling OnAfterRender by default
This commit is contained in:
parent
706309f266
commit
521cabc545
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -21,6 +22,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
|||
"area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"
|
||||
};
|
||||
|
||||
private static readonly Task CanceledRenderTask = Task.FromCanceled(new CancellationToken(canceled: true));
|
||||
|
||||
private readonly Func<string, string> _htmlEncoder;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -40,7 +43,19 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
|||
/// <inheritdoc />
|
||||
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
// By default we return a canceled task. This has the effect of making it so that the
|
||||
// OnAfterRenderAsync callbacks on components don't run by default.
|
||||
// This way, by default prerendering gets the correct behavior and other renderers
|
||||
// override the UpdateDisplayAsync method already, so those components can
|
||||
// either complete a task when the client acknowledges the render, or return a canceled task
|
||||
// when the renderer gets disposed.
|
||||
|
||||
// We believe that returning a canceled task is the right behavior as we expect that any class
|
||||
// that subclasses this class to provide an implementation for a given rendering scenario respects
|
||||
// the contract that OnAfterRender should only be called when the display has successfully been updated
|
||||
// and the application is interactive. (Element and component references are populated and JavaScript interop
|
||||
// is available).
|
||||
return CanceledRenderTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -445,8 +445,12 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
|||
{
|
||||
if (updateDisplayTask.IsCanceled)
|
||||
{
|
||||
// The display update was cancelled (maybe due to a timeout on the components server-side case or due
|
||||
// to the renderer being disposed)
|
||||
// The display update was canceled.
|
||||
// This can be due to a timeout on the components server-side case, or the renderer being disposed.
|
||||
|
||||
// The latter case is normal during prerendering, as the render never fully completes (the display never
|
||||
// gets updated, no references get populated and JavaScript interop is not available) and we simply discard
|
||||
// the renderer after producing the prerendered content.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
if (updateDisplayTask.IsFaulted)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,26 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Test
|
|||
Assert.Equal("<p>Hello Steve!</p>", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderComponent_DoesNotInvokeOnAfterRenderInComponent()
|
||||
{
|
||||
// Arrange
|
||||
var helper = CreateHelper();
|
||||
var writer = new StringWriter();
|
||||
|
||||
// Act
|
||||
var state = new OnAfterRenderState();
|
||||
var result = await helper.RenderComponentAsync<OnAfterRenderComponent>(new
|
||||
{
|
||||
State = state
|
||||
});
|
||||
result.WriteTo(writer, HtmlEncoder.Default);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("<p>Hello</p>", writer.ToString());
|
||||
Assert.False(state.OnAfterRenderRan);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanCatch_ComponentWithSynchronousException()
|
||||
{
|
||||
|
|
@ -309,6 +329,26 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Test
|
|||
}
|
||||
}
|
||||
|
||||
private class OnAfterRenderComponent : ComponentBase
|
||||
{
|
||||
[Parameter] public OnAfterRenderState State { get; set; }
|
||||
|
||||
protected override void OnAfterRender()
|
||||
{
|
||||
State.OnAfterRenderRan = true;
|
||||
}
|
||||
|
||||
protected override void BuildRenderTree(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.AddMarkupContent(0, "<p>Hello</p>");
|
||||
}
|
||||
}
|
||||
|
||||
private class OnAfterRenderState
|
||||
{
|
||||
public bool OnAfterRenderRan { get; set; }
|
||||
}
|
||||
|
||||
private class GreetingComponent : ComponentBase
|
||||
{
|
||||
[Parameter] public string Name { get; set; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue