Skip to content

Commit a10f5c0

Browse files
committed
Optimization
1 parent 2996e5c commit a10f5c0

File tree

3 files changed

+63
-62
lines changed

3 files changed

+63
-62
lines changed

src/Components/Shared/src/JsonSerialization/JsonConverterFactoryTypeInfoResolver.cs

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

src/Components/Web/src/Microsoft.AspNetCore.Components.Web.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
<Compile Include="$(ComponentsSharedSourceRoot)src\AttributeUtilities.cs" LinkBase="Forms" />
1919
<Compile Include="$(ComponentsSharedSourceRoot)src\ExpressionFormatting\**\*.cs" LinkBase="Forms\ExpressionFommatting" />
2020
<Compile Include="$(ComponentsSharedSourceRoot)src\DefaultAntiforgeryStateProvider.cs" LinkBase="Forms" />
21-
<Compile Include="$(ComponentsSharedSourceRoot)src\JsonSerialization\JsonConverterFactoryTypeInfoResolver.cs" LinkBase="JsonSerialization" />
2221
</ItemGroup>
2322

2423
<ItemGroup>

src/Components/Web/src/WebRenderer.cs

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics.CodeAnalysis;
5+
using System.Globalization;
56
using System.Text.Json;
67
using System.Text.Json.Serialization;
8+
using System.Text.Json.Serialization.Metadata;
79
using Microsoft.AspNetCore.Components.Web;
810
using Microsoft.AspNetCore.Components.Web.Infrastructure;
911
using Microsoft.AspNetCore.Components.Web.Internal;
@@ -100,33 +102,76 @@ protected override void Dispose(bool disposing)
100102
base.Dispose(disposing);
101103
}
102104

103-
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
104105
private void AttachWebRendererInterop(IJSRuntime jsRuntime, JsonSerializerOptions jsonOptions, JSComponentInterop jsComponentInterop)
105106
{
106107
const string JSMethodIdentifier = "Blazor._internal.attachWebRendererInterop";
107108

108-
object[] args = [
109-
_rendererId,
110-
_interopMethodsReference,
111-
jsComponentInterop.Configuration.JSComponentParametersByIdentifier,
112-
jsComponentInterop.Configuration.JSComponentIdentifiersByInitializer,
113-
];
114-
115109
if (jsRuntime is IInternalWebJSInProcessRuntime inProcessRuntime)
116110
{
117-
var newJsonOptions = new JsonSerializerOptions(jsonOptions);
118-
newJsonOptions.TypeInfoResolverChain.Clear();
119-
newJsonOptions.TypeInfoResolverChain.Add(WebRendererSerializerContext.Default);
120-
newJsonOptions.TypeInfoResolverChain.Add(JsonConverterFactoryTypeInfoResolver<DotNetObjectReference<WebRendererInteropMethods>>.Instance);
121-
var argsJson = JsonSerializer.Serialize(args, newJsonOptions);
111+
// Fast path for WebAssembly: Rather than using the JSRuntime to serialize
112+
// parameters, we utilize the source-generated WebRendererSerializerContext
113+
// for a faster JsonTypeInfo resolution.
114+
115+
// We resolve a JsonTypeInfo for DotNetObjectReference<WebRendererInteropMethods> from
116+
// the JS runtime's JsonConverters. This is because adding DotNetObjectReference<T> as
117+
// a supported type in the JsonSerializerContext generates unnecessary code to produce
118+
// JsonTypeInfo for all the types referenced by both DotNetObjectReference<T> and its
119+
// generic type argument.
120+
var interopMethodsReferenceJsonTypeInfo = GetJsonTypeInfoFromJsonConverterFactories<DotNetObjectReference<WebRendererInteropMethods>>(
121+
jsonOptions.Converters,
122+
WebRendererSerializerContext.Default.Options);
123+
124+
var rendererIdJson = _rendererId.ToString(CultureInfo.InvariantCulture);
125+
var interopMethodsReferenceJson = JsonSerializer.Serialize(
126+
_interopMethodsReference,
127+
interopMethodsReferenceJsonTypeInfo);
128+
var jsComponentParametersByIdentifierJson = JsonSerializer.Serialize(
129+
jsComponentInterop.Configuration.JSComponentParametersByIdentifier,
130+
WebRendererSerializerContext.Default.DictionaryStringJSComponentParameterArray);
131+
var jsComponentIdentifiersByInitializerJson = JsonSerializer.Serialize(
132+
jsComponentInterop.Configuration.JSComponentIdentifiersByInitializer,
133+
WebRendererSerializerContext.Default.DictionaryStringListString);
134+
135+
var argsJson =
136+
$"[{rendererIdJson}, " +
137+
$"{interopMethodsReferenceJson}, " +
138+
$"{jsComponentParametersByIdentifierJson}, " +
139+
$"{jsComponentIdentifiersByInitializerJson}]";
122140
inProcessRuntime.InvokeJS(JSMethodIdentifier, argsJson, JSCallResultType.JSVoidResult, 0);
123141
}
124142
else
125143
{
126-
jsRuntime.InvokeVoidAsync(JSMethodIdentifier, args).Preserve();
144+
jsRuntime.InvokeVoidAsync(
145+
JSMethodIdentifier,
146+
_rendererId,
147+
_interopMethodsReference,
148+
jsComponentInterop.Configuration.JSComponentParametersByIdentifier,
149+
jsComponentInterop.Configuration.JSComponentIdentifiersByInitializer).Preserve();
127150
}
128151
}
129152

153+
private static JsonTypeInfo<T> GetJsonTypeInfoFromJsonConverterFactories<T>(
154+
IList<JsonConverter> converters,
155+
JsonSerializerOptions optionsToUse)
156+
{
157+
foreach (var converter in converters)
158+
{
159+
if (converter is not JsonConverterFactory factory || !factory.CanConvert(typeof(T)))
160+
{
161+
continue;
162+
}
163+
164+
if (factory.CreateConverter(typeof(T), optionsToUse) is not { } converterToUse)
165+
{
166+
continue;
167+
}
168+
169+
return JsonMetadataServices.CreateValueInfo<T>(optionsToUse, converterToUse);
170+
}
171+
172+
throw new InvalidOperationException($"Could not create a JsonTypeInfo for type {typeof(T).FullName}");
173+
}
174+
130175
/// <summary>
131176
/// A collection of JS invokable methods that the JS-side code can use when it needs to
132177
/// make calls in the context of a particular renderer. This object is never exposed to
@@ -170,8 +215,10 @@ public void RemoveRootComponent(int componentId)
170215
}
171216
}
172217

173-
[JsonSerializable(typeof(object[]))]
174-
[JsonSerializable(typeof(int))]
218+
[JsonSourceGenerationOptions(
219+
GenerationMode = JsonSourceGenerationMode.Serialization,
220+
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
221+
PropertyNameCaseInsensitive = true)]
175222
[JsonSerializable(typeof(Dictionary<string, JSComponentConfigurationStore.JSComponentParameter[]>))]
176223
[JsonSerializable(typeof(Dictionary<string, List<string>>))]
177224
internal sealed partial class WebRendererSerializerContext : JsonSerializerContext;

0 commit comments

Comments
 (0)