Skip to content

Commit d0301de

Browse files
committed
Improvements and cleanup
1 parent 2bef3c4 commit d0301de

32 files changed

+480
-845
lines changed

src/Components/Endpoints/src/DependencyInjection/AutoComponentMarker.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Components/Endpoints/src/DependencyInjection/AutoComponentSerializer.cs

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/Components/Endpoints/src/DependencyInjection/ServerComponentSerializer.cs

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,17 @@ namespace Microsoft.AspNetCore.Components.Endpoints;
99
// See the details of the component serialization protocol in ServerComponentDeserializer.cs on the Components solution.
1010
internal sealed class ServerComponentSerializer
1111
{
12-
public const int PreambleBufferSize = 3;
13-
1412
private readonly ITimeLimitedDataProtector _dataProtector;
1513

1614
public ServerComponentSerializer(IDataProtectionProvider dataProtectionProvider) =>
1715
_dataProtector = dataProtectionProvider
1816
.CreateProtector(ServerComponentSerializationSettings.DataProtectionProviderPurpose)
1917
.ToTimeLimitedDataProtector();
2018

21-
public ServerComponentMarker SerializeInvocation(ServerComponentInvocationSequence invocationId, Type type, ParameterView parameters, string key, bool prerendered)
19+
public void SerializeInvocation(ref ComponentMarker marker, ServerComponentInvocationSequence invocationId, Type type, ParameterView parameters)
2220
{
2321
var (sequence, serverComponent) = CreateSerializedServerComponent(invocationId, type, parameters);
24-
return prerendered ? ServerComponentMarker.Prerendered(sequence, serverComponent, key) : ServerComponentMarker.NonPrerendered(sequence, serverComponent, key);
22+
marker.WriteServerData(sequence, serverComponent);
2523
}
2624

2725
private (int sequence, string payload) CreateSerializedServerComponent(
@@ -45,29 +43,4 @@ public ServerComponentMarker SerializeInvocation(ServerComponentInvocationSequen
4543
var protectedBytes = _dataProtector.Protect(serializedServerComponentBytes, ServerComponentSerializationSettings.DataExpiration);
4644
return (serverComponent.Sequence, Convert.ToBase64String(protectedBytes));
4745
}
48-
49-
/// <remarks>
50-
/// Remember to update <see cref="PreambleBufferSize"/> if the number of entries being appended in this function changes.
51-
/// </remarks>
52-
internal static void AppendPreamble(TextWriter writer, ServerComponentMarker record)
53-
{
54-
var serializedStartRecord = JsonSerializer.Serialize(
55-
record,
56-
ServerComponentSerializationSettings.JsonSerializationOptions);
57-
58-
writer.Write("<!--Blazor:");
59-
writer.Write(serializedStartRecord);
60-
writer.Write("-->");
61-
}
62-
63-
internal static void AppendEpilogue(TextWriter writer, ServerComponentMarker record)
64-
{
65-
var endRecord = JsonSerializer.Serialize(
66-
record.GetEndRecord(),
67-
ServerComponentSerializationSettings.JsonSerializationOptions);
68-
69-
writer.Write("<!--Blazor:");
70-
writer.Write(endRecord);
71-
writer.Write("-->");
72-
}
7346
}

src/Components/Endpoints/src/DependencyInjection/WebAssemblyComponentSerializer.cs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Components.Endpoints;
88
// See the details of the component serialization protocol in WebAssemblyComponentDeserializer.cs on the Components solution.
99
internal sealed class WebAssemblyComponentSerializer
1010
{
11-
public static WebAssemblyComponentMarker SerializeInvocation(Type type, ParameterView parameters, string? key, bool prerendered)
11+
public static void SerializeInvocation(ref ComponentMarker marker, Type type, ParameterView parameters)
1212
{
1313
var assembly = type.Assembly.GetName().Name ?? throw new InvalidOperationException("Cannot prerender components from assemblies with a null name");
1414
var typeFullName = type.FullName ?? throw new InvalidOperationException("Cannot prerender component types with a null name");
@@ -19,29 +19,6 @@ public static WebAssemblyComponentMarker SerializeInvocation(Type type, Paramete
1919
var serializedDefinitions = Convert.ToBase64String(JsonSerializer.SerializeToUtf8Bytes(definitions, WebAssemblyComponentSerializationSettings.JsonSerializationOptions));
2020
var serializedValues = Convert.ToBase64String(JsonSerializer.SerializeToUtf8Bytes(values, WebAssemblyComponentSerializationSettings.JsonSerializationOptions));
2121

22-
return prerendered ? WebAssemblyComponentMarker.Prerendered(assembly, typeFullName, serializedDefinitions, serializedValues, key) :
23-
WebAssemblyComponentMarker.NonPrerendered(assembly, typeFullName, serializedDefinitions, serializedValues, key);
24-
}
25-
26-
internal static void AppendPreamble(TextWriter writer, WebAssemblyComponentMarker record)
27-
{
28-
var serializedStartRecord = JsonSerializer.Serialize(
29-
record,
30-
WebAssemblyComponentSerializationSettings.JsonSerializationOptions);
31-
32-
writer.Write("<!--Blazor:");
33-
writer.Write(serializedStartRecord);
34-
writer.Write("-->");
35-
}
36-
37-
internal static void AppendEpilogue(TextWriter writer, WebAssemblyComponentMarker record)
38-
{
39-
var endRecord = JsonSerializer.Serialize(
40-
record.GetEndRecord(),
41-
WebAssemblyComponentSerializationSettings.JsonSerializationOptions);
42-
43-
writer.Write("<!--Blazor:");
44-
writer.Write(endRecord);
45-
writer.Write("-->");
22+
marker.WriteWebAssemblyData(assembly, typeFullName, serializedDefinitions, serializedValues);
4623
}
4724
}

src/Components/Endpoints/src/Microsoft.AspNetCore.Components.Endpoints.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@
2525
</ItemGroup>
2626

2727
<ItemGroup>
28+
<Compile Include="$(SharedSourceRoot)Components\ComponentMarker.cs" LinkBase="DependencyInjection" />
2829
<Compile Include="$(SharedSourceRoot)Components\WebAssemblyComponentSerializationSettings.cs" LinkBase="DependencyInjection" />
2930
<Compile Include="$(SharedSourceRoot)Components\ServerComponentSerializationSettings.cs" LinkBase="DependencyInjection" />
30-
<Compile Include="$(SharedSourceRoot)Components\WebAssemblyComponentMarker.cs" LinkBase="DependencyInjection" />
31-
<Compile Include="$(SharedSourceRoot)Components\ServerComponentMarker.cs" LinkBase="DependencyInjection" />
3231
<Compile Include="$(SharedSourceRoot)Components\ServerComponent.cs" LinkBase="DependencyInjection" />
3332
<Compile Include="$(RepoRoot)src\Shared\Components\ComponentParameter.cs" LinkBase="DependencyInjection" />
3433
<Compile Include="$(RepoRoot)src\Shared\Components\PrerenderComponentApplicationStore.cs" LinkBase="DependencyInjection" />

src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Streaming.cs

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Runtime.InteropServices;
55
using System.Text.Encodings.Web;
6+
using System.Text.Json;
67
using Microsoft.AspNetCore.Components.RenderTree;
78
using Microsoft.AspNetCore.Hosting;
89
using Microsoft.AspNetCore.Http;
@@ -199,35 +200,22 @@ private void WriteComponentHtml(int componentId, TextWriter output, bool allowBo
199200
var componentState = (EndpointComponentState)GetComponentState(componentId);
200201
var renderBoundaryMarkers = allowBoundaryMarkers && componentState.StreamRendering;
201202

202-
// TODO: It's not clear that we actually want to emit the interactive component markers using this
203-
// HTML-comment syntax that we've used historically, plus we likely want some way to coalesce both
204-
// marker types into a single thing for auto mode (the code below emits both separately for auto).
205-
// It may be better to use a custom element like <blazor-component ...>[prerendered]<blazor-component>
206-
// so it's easier for the JS code to react automatically whenever this gets inserted or updated during
207-
// streaming SSR or progressively-enhanced navigation.
208-
var (serverMarker, webAssemblyMarker) = componentState.Component is SSRRenderModeBoundary boundary
209-
? boundary.ToMarkers(_httpContext, sequenceAndKey.Sequence, sequenceAndKey.Key)
210-
: default;
211-
212-
if (serverMarker.HasValue)
203+
ComponentEndMarker? endMarkerOrNull = default;
204+
205+
if (componentState.Component is SSRRenderModeBoundary boundary)
213206
{
214-
if (!_httpContext.Response.HasStarted)
207+
var marker = boundary.ToMarker(_httpContext, sequenceAndKey.Sequence, sequenceAndKey.Key);
208+
endMarkerOrNull = marker.ToEndMarker();
209+
210+
if (!_httpContext.Response.HasStarted && marker.Type is ComponentMarker.ServerMarkerType or ComponentMarker.WebAssemblyMarkerType)
215211
{
216212
_httpContext.Response.Headers.CacheControl = "no-cache, no-store, max-age=0";
217213
}
218214

219-
if (webAssemblyMarker.HasValue)
220-
{
221-
AutoComponentSerializer.AppendPreamble(output, serverMarker.Value, webAssemblyMarker.Value);
222-
}
223-
else
224-
{
225-
ServerComponentSerializer.AppendPreamble(output, serverMarker.Value);
226-
}
227-
}
228-
else if (webAssemblyMarker.HasValue)
229-
{
230-
WebAssemblyComponentSerializer.AppendPreamble(output, webAssemblyMarker.Value);
215+
var serializedStartRecord = JsonSerializer.Serialize(marker, ServerComponentSerializationSettings.JsonSerializationOptions);
216+
output.Write("<!--Blazor:");
217+
output.Write(serializedStartRecord);
218+
output.Write("-->");
231219
}
232220

233221
if (renderBoundaryMarkers)
@@ -246,26 +234,12 @@ private void WriteComponentHtml(int componentId, TextWriter output, bool allowBo
246234
output.Write("-->");
247235
}
248236

249-
if (serverMarker.HasValue)
237+
if (endMarkerOrNull is { } endMarker)
250238
{
251-
if (serverMarker.Value.PrerenderId is not null)
252-
{
253-
if (webAssemblyMarker.HasValue)
254-
{
255-
AutoComponentSerializer.AppendEpilogue(output, serverMarker.Value);
256-
}
257-
else
258-
{
259-
ServerComponentSerializer.AppendEpilogue(output, serverMarker.Value);
260-
}
261-
}
262-
}
263-
else if (webAssemblyMarker.HasValue)
264-
{
265-
if (webAssemblyMarker.Value.PrerenderId is not null)
266-
{
267-
WebAssemblyComponentSerializer.AppendEpilogue(output, webAssemblyMarker.Value);
268-
}
239+
var serializedEndRecord = JsonSerializer.Serialize(endMarker, ServerComponentSerializationSettings.JsonSerializationOptions);
240+
output.Write("<!--Blazor:");
241+
output.Write(serializedEndRecord);
242+
output.Write("-->");
269243
}
270244
}
271245

src/Components/Endpoints/src/Rendering/SSRRenderModeBoundary.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Diagnostics;
45
using System.Globalization;
56
using System.Security.Cryptography;
67
using System.Text;
@@ -98,7 +99,7 @@ private void Prerender(RenderTreeBuilder builder)
9899
builder.CloseComponent();
99100
}
100101

101-
public (ServerComponentMarker?, WebAssemblyComponentMarker?) ToMarkers(HttpContext httpContext, int sequence, object? key)
102+
public ComponentMarker ToMarker(HttpContext httpContext, int sequence, object? key)
102103
{
103104
// We expect that the '@key' and sequence number shouldn't change for a given component instance,
104105
// so we lazily compute the marker key once.
@@ -108,24 +109,30 @@ private void Prerender(RenderTreeBuilder builder)
108109
? ParameterView.Empty
109110
: ParameterView.FromDictionary((IDictionary<string, object?>)_latestParameters);
110111

111-
ServerComponentMarker? serverMarker = null;
112+
var marker = _renderMode switch
113+
{
114+
ServerRenderMode server => ComponentMarker.Create(ComponentMarker.ServerMarkerType, server.Prerender, _markerKey),
115+
WebAssemblyRenderMode webAssembly => ComponentMarker.Create(ComponentMarker.WebAssemblyMarkerType, webAssembly.Prerender, _markerKey),
116+
AutoRenderMode auto => ComponentMarker.Create(ComponentMarker.AutoMarkerType, auto.Prerender, _markerKey),
117+
_ => throw new UnreachableException($"Unknown render mode {_renderMode.GetType().FullName}"),
118+
};
119+
112120
if (_renderMode is ServerRenderMode or AutoRenderMode)
113121
{
114122
// Lazy because we don't actually want to require a whole chain of services including Data Protection
115123
// to be required unless you actually use Server render mode.
116124
var serverComponentSerializer = httpContext.RequestServices.GetRequiredService<ServerComponentSerializer>();
117125

118126
var invocationId = EndpointHtmlRenderer.GetOrCreateInvocationId(httpContext);
119-
serverMarker = serverComponentSerializer.SerializeInvocation(invocationId, _componentType, parameters, _markerKey, _prerender);
127+
serverComponentSerializer.SerializeInvocation(ref marker, invocationId, _componentType, parameters);
120128
}
121129

122-
WebAssemblyComponentMarker? webAssemblyMarker = null;
123130
if (_renderMode is WebAssemblyRenderMode or AutoRenderMode)
124131
{
125-
webAssemblyMarker = WebAssemblyComponentSerializer.SerializeInvocation(_componentType, parameters, _markerKey, _prerender);
132+
WebAssemblyComponentSerializer.SerializeInvocation(ref marker, _componentType, parameters);
126133
}
127134

128-
return (serverMarker, webAssemblyMarker);
135+
return marker;
129136
}
130137

131138
private string GenerateMarkerKey(int sequence, object? key)

0 commit comments

Comments
 (0)