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

Use view buffers during pre-rendering #39465

Merged
merged 2 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Components.Server" />
<Reference Include="Microsoft.AspNetCore.Html.Abstractions" />
</ItemGroup>

<PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Mvc/Mvc.TagHelpers/test/ComponentTagHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private ViewContext GetViewContext()
{
var htmlContent = new HtmlContentBuilder().AppendHtml("Hello world");
var renderer = Mock.Of<IComponentRenderer>(c =>
c.RenderComponentAsync(It.IsAny<ViewContext>(), It.IsAny<Type>(), It.IsAny<RenderMode>(), It.IsAny<object>()) == Task.FromResult<IHtmlContent>(htmlContent));
c.RenderComponentAsync(It.IsAny<ViewContext>(), It.IsAny<Type>(), It.IsAny<RenderMode>(), It.IsAny<object>()) == new ValueTask<IHtmlContent>(htmlContent));

var httpContext = new DefaultHttpContext
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -180,7 +181,7 @@ private ViewContext GetViewContext()
{
var htmlContent = new HtmlContentBuilder().AppendHtml("Hello world");
var renderer = Mock.Of<IComponentRenderer>(c =>
c.RenderComponentAsync(It.IsAny<ViewContext>(), It.IsAny<Type>(), It.IsAny<RenderMode>(), It.IsAny<object>()) == Task.FromResult<IHtmlContent>(htmlContent));
c.RenderComponentAsync(It.IsAny<ViewContext>(), It.IsAny<Type>(), It.IsAny<RenderMode>(), It.IsAny<object>()) == new ValueTask<IHtmlContent>(htmlContent));

var httpContext = new DefaultHttpContext
{
Expand All @@ -191,6 +192,7 @@ private ViewContext GetViewContext()
.AddSingleton(_ephemeralProvider)
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
.AddSingleton(HtmlEncoder.Default)
.AddScoped<IViewBufferScope, TestViewBufferScope>()
.BuildServiceProvider(),
};

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Html;

namespace Microsoft.AspNetCore.Components.Rendering;

internal readonly struct ComponentRenderedText
{
public ComponentRenderedText(int componentId, IEnumerable<string> tokens)
public ComponentRenderedText(int componentId, IHtmlContent htmlContent)
{
ComponentId = componentId;
Tokens = tokens;
HtmlContent = htmlContent;
}

public int ComponentId { get; }

public IEnumerable<string> Tokens { get; }
public IHtmlContent HtmlContent { get; }
}
68 changes: 28 additions & 40 deletions src/Mvc/Mvc.ViewFeatures/src/RazorComponents/ComponentRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,30 @@
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers;

namespace Microsoft.AspNetCore.Mvc.ViewFeatures;

internal class ComponentRenderer : IComponentRenderer
internal sealed class ComponentRenderer : IComponentRenderer
{
private static readonly object ComponentSequenceKey = new object();
private static readonly object InvokedRenderModesKey = new object();

private readonly StaticComponentRenderer _staticComponentRenderer;
private readonly ServerComponentSerializer _serverComponentSerializer;
private readonly WebAssemblyComponentSerializer _WebAssemblyComponentSerializer;
private readonly IViewBufferScope _viewBufferScope;

public ComponentRenderer(
StaticComponentRenderer staticComponentRenderer,
ServerComponentSerializer serverComponentSerializer,
WebAssemblyComponentSerializer WebAssemblyComponentSerializer)
IViewBufferScope viewBufferScope)
{
_staticComponentRenderer = staticComponentRenderer;
_serverComponentSerializer = serverComponentSerializer;
_WebAssemblyComponentSerializer = WebAssemblyComponentSerializer;
_viewBufferScope = viewBufferScope;
}

public async Task<IHtmlContent> RenderComponentAsync(
public async ValueTask<IHtmlContent> RenderComponentAsync(
ViewContext viewContext,
Type componentType,
RenderMode renderMode,
Expand Down Expand Up @@ -117,14 +118,12 @@ internal static InvokedRenderModes.Mode GetPersistStateRenderMode(ViewContext vi
}
}

private async Task<IHtmlContent> StaticComponentAsync(HttpContext context, Type type, ParameterView parametersCollection)
private ValueTask<IHtmlContent> StaticComponentAsync(HttpContext context, Type type, ParameterView parametersCollection)
{
var result = await _staticComponentRenderer.PrerenderComponentAsync(
return _staticComponentRenderer.PrerenderComponentAsync(
parametersCollection,
context,
type);

return new ComponentHtmlContent(result);
}

private async Task<IHtmlContent> PrerenderedServerComponentAsync(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection)
Expand All @@ -145,13 +144,15 @@ private async Task<IHtmlContent> PrerenderedServerComponentAsync(HttpContext con
context,
type);

return new ComponentHtmlContent(
ServerComponentSerializer.GetPreamble(currentInvocation),
result,
ServerComponentSerializer.GetEpilogue(currentInvocation));
var viewBuffer = new ViewBuffer(_viewBufferScope, nameof(ComponentRenderer), ViewBuffer.ViewPageSize);
ServerComponentSerializer.AppendPreamble(viewBuffer, currentInvocation);
viewBuffer.AppendHtml(result);
ServerComponentSerializer.AppendEpilogue(viewBuffer, currentInvocation);

return viewBuffer;
}

private async Task<IHtmlContent> PrerenderedWebAssemblyComponentAsync(HttpContext context, Type type, ParameterView parametersCollection)
private async ValueTask<IHtmlContent> PrerenderedWebAssemblyComponentAsync(HttpContext context, Type type, ParameterView parametersCollection)
{
var currentInvocation = WebAssemblyComponentSerializer.SerializeInvocation(
type,
Expand All @@ -163,10 +164,12 @@ private async Task<IHtmlContent> PrerenderedWebAssemblyComponentAsync(HttpContex
context,
type);

return new ComponentHtmlContent(
WebAssemblyComponentSerializer.GetPreamble(currentInvocation),
result,
WebAssemblyComponentSerializer.GetEpilogue(currentInvocation));
var viewBuffer = new ViewBuffer(_viewBufferScope, nameof(ComponentRenderer), ViewBuffer.ViewPageSize);
WebAssemblyComponentSerializer.AppendPreamble(viewBuffer, currentInvocation);
viewBuffer.AppendHtml(result);
WebAssemblyComponentSerializer.AppendEpilogue(viewBuffer, currentInvocation);

return viewBuffer;
}

private IHtmlContent NonPrerenderedServerComponent(HttpContext context, ServerComponentInvocationSequence invocationId, Type type, ParameterView parametersCollection)
Expand All @@ -178,31 +181,16 @@ private IHtmlContent NonPrerenderedServerComponent(HttpContext context, ServerCo

var currentInvocation = _serverComponentSerializer.SerializeInvocation(invocationId, type, parametersCollection, prerendered: false);

return new ComponentHtmlContent(ServerComponentSerializer.GetPreamble(currentInvocation));
var viewBuffer = new ViewBuffer(_viewBufferScope, nameof(ComponentRenderer), ServerComponentSerializer.PreambleBufferSize);
ServerComponentSerializer.AppendPreamble(viewBuffer, currentInvocation);
return viewBuffer;
}

private static IHtmlContent NonPrerenderedWebAssemblyComponent(HttpContext context, Type type, ParameterView parametersCollection)
private IHtmlContent NonPrerenderedWebAssemblyComponent(HttpContext context, Type type, ParameterView parametersCollection)
{
var currentInvocation = WebAssemblyComponentSerializer.SerializeInvocation(type, parametersCollection, prerendered: false);

return new ComponentHtmlContent(WebAssemblyComponentSerializer.GetPreamble(currentInvocation));
}
}

internal class InvokedRenderModes
{
public InvokedRenderModes(Mode mode)
{
Value = mode;
}

public Mode Value { get; set; }

internal enum Mode
{
None,
Server,
WebAssembly,
ServerAndWebAssembly
var viewBuffer = new ViewBuffer(_viewBufferScope, nameof(ComponentRenderer), ServerComponentSerializer.PreambleBufferSize);
WebAssemblyComponentSerializer.AppendPreamble(viewBuffer, currentInvocation);
return viewBuffer;
}
}
Loading