-
Notifications
You must be signed in to change notification settings - Fork 9.8k
/
StaticHtmlRenderer.cs
101 lines (87 loc) · 4.86 KB
/
StaticHtmlRenderer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.ExceptionServices;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.HtmlRendering;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Components.HtmlRendering.Infrastructure;
/// <summary>
/// A <see cref="Renderer"/> subclass that is intended for static HTML rendering. Application
/// developers should not normally use this class directly. Instead, use
/// <see cref="HtmlRenderer"/> for a more convenient API.
/// </summary>
public partial class StaticHtmlRenderer : Renderer
{
private static readonly Task CanceledRenderTask = Task.FromCanceled(new CancellationToken(canceled: true));
private readonly NavigationManager? _navigationManager;
/// <summary>
/// Constructs an instance of <see cref="StaticHtmlRenderer"/>.
/// </summary>
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> to be used when initializing components.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public StaticHtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory)
: base(serviceProvider, loggerFactory)
{
_navigationManager = serviceProvider.GetService<NavigationManager>();
_htmlEncoder = serviceProvider.GetService<HtmlEncoder>() ?? HtmlEncoder.Default;
_javaScriptEncoder = serviceProvider.GetService<JavaScriptEncoder>() ?? JavaScriptEncoder.Default;
}
/// <inheritdoc/>
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
/// <summary>
/// Adds a root component of the specified type and begins rendering it.
/// </summary>
/// <param name="componentType">The component type. This must implement <see cref="IComponent"/>.</param>
/// <param name="initialParameters">Parameters for the component.</param>
/// <returns>An <see cref="HtmlRootComponent"/> that can be used to obtain the rendered HTML.</returns>
public HtmlRootComponent BeginRenderingComponent(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type componentType,
ParameterView initialParameters)
{
var component = InstantiateComponent(componentType);
return BeginRenderingComponent(component, initialParameters);
}
/// <summary>
/// Adds a root component and begins rendering it.
/// </summary>
/// <param name="component">The root component instance to be added and rendered. This must not already be associated with any renderer.</param>
/// <param name="initialParameters">Parameters for the component.</param>
/// <returns>An <see cref="HtmlRootComponent"/> that can be used to obtain the rendered HTML.</returns>
public HtmlRootComponent BeginRenderingComponent(
IComponent component,
ParameterView initialParameters)
{
var componentId = AssignRootComponentId(component);
var quiescenceTask = RenderRootComponentAsync(componentId, initialParameters);
if (quiescenceTask.IsFaulted)
{
ExceptionDispatchInfo.Capture(quiescenceTask.Exception.InnerException ?? quiescenceTask.Exception).Throw();
}
return new HtmlRootComponent(this, componentId, quiescenceTask);
}
/// <inheritdoc/>
protected override void HandleException(Exception exception)
=> ExceptionDispatchInfo.Capture(exception).Throw();
/// <inheritdoc/>
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
{
// 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;
}
internal new ArrayRange<RenderTreeFrame> GetCurrentRenderTreeFrames(int componentId)
=> base.GetCurrentRenderTreeFrames(componentId);
}