Skip to content

Commit b05f4cb

Browse files
authored
[Blazor] Resolve collection for registered services once (#61391)
* Avoid checking the shared cache on a per-request basis to resolve the type for existing persistent service registrations * Avoid resolving registrations on a per-request basis
1 parent d75d9b3 commit b05f4cb

File tree

6 files changed

+32
-7
lines changed

6 files changed

+32
-7
lines changed

src/Components/Components/src/PersistentState/IPersistentServiceRegistration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ internal interface IPersistentServiceRegistration
1010
public string FullTypeName { get; }
1111

1212
public IComponentRenderMode? GetRenderModeOrDefault();
13+
14+
public Type? GetResolvedTypeOrNull() => null;
1315
}

src/Components/Components/src/PersistentState/PersistentServiceRegistration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ internal sealed class PersistentServiceRegistration<TService>(IComponentRenderMo
1313

1414
public IComponentRenderMode? GetRenderModeOrDefault() => componentRenderMode;
1515

16+
public Type? GetResolvedTypeOrNull() => typeof(TService);
17+
1618
private string GetDebuggerDisplay() => $"{Assembly}::{FullTypeName}";
1719
}

src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ internal sealed class PersistentServicesRegistry
2626

2727
public PersistentServicesRegistry(IServiceProvider serviceProvider)
2828
{
29-
var registrations = serviceProvider.GetRequiredService<IEnumerable<IPersistentServiceRegistration>>();
3029
_serviceProvider = serviceProvider;
31-
_registrations = ResolveRegistrations(registrations);
30+
_registrations = ResolveRegistrations(serviceProvider.GetService<RegisteredPersistentServiceRegistrationCollection>()?.Registrations ?? []);
3231
}
3332

3433
internal IComponentRenderMode? RenderMode { get; set; }
@@ -50,7 +49,7 @@ internal void RegisterForPersistence(PersistentComponentState state)
5049
for (var i = 0; i < _registrations.Length; i++)
5150
{
5251
var registration = _registrations[i];
53-
var type = ResolveType(registration.Assembly, registration.FullTypeName);
52+
var type = ResolveType(registration);
5453
if (type == null)
5554
{
5655
continue;
@@ -112,7 +111,7 @@ private void RestoreRegistrationsIfAvailable(PersistentComponentState state)
112111
{
113112
foreach (var registration in _registrations)
114113
{
115-
var type = ResolveType(registration.Assembly, registration.FullTypeName);
114+
var type = ResolveType(registration);
116115
if (type == null)
117116
{
118117
continue;
@@ -140,10 +139,18 @@ private static void RestoreInstanceState(object instance, Type type, PersistentC
140139
}
141140
}
142141

143-
private static IPersistentServiceRegistration[] ResolveRegistrations(IEnumerable<IPersistentServiceRegistration> registrations) => [.. registrations.DistinctBy(r => (r.Assembly, r.FullTypeName)).OrderBy(r => r.Assembly).ThenBy(r => r.FullTypeName)];
142+
internal static IPersistentServiceRegistration[] ResolveRegistrations(IEnumerable<IPersistentServiceRegistration> registrations) => [.. registrations.DistinctBy(r => (r.Assembly, r.FullTypeName)).OrderBy(r => r.Assembly).ThenBy(r => r.FullTypeName)];
144143

145-
private static Type? ResolveType(string assembly, string fullTypeName) =>
146-
_persistentServiceTypeCache.GetRootType(assembly, fullTypeName);
144+
private static Type? ResolveType(IPersistentServiceRegistration registration)
145+
{
146+
if (registration.GetResolvedTypeOrNull() is Type type)
147+
{
148+
return type;
149+
}
150+
var assembly = registration.Assembly;
151+
var fullTypeName = registration.FullTypeName;
152+
return _persistentServiceTypeCache.GetRootType(assembly, fullTypeName);
153+
}
147154

148155
private sealed class PropertiesAccessor
149156
{
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.AspNetCore.Components.Infrastructure;
5+
6+
internal class RegisteredPersistentServiceRegistrationCollection(IEnumerable<IPersistentServiceRegistration> registrations)
7+
{
8+
private readonly IEnumerable<IPersistentServiceRegistration> _registrations =
9+
PersistentServicesRegistry.ResolveRegistrations(registrations);
10+
11+
public IEnumerable<IPersistentServiceRegistration> Registrations => _registrations;
12+
}

src/Components/Components/src/RegisterPersistentComponentStateServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public static class RegisterPersistentComponentStateServiceCollectionExtensions
3636
// We resolve the service from the DI container.
3737
// We loop through the properties in the type and try to restore the properties that have SupplyParameterFromPersistentComponentState on them.
3838
services.TryAddEnumerable(ServiceDescriptor.Singleton<IPersistentServiceRegistration>(new PersistentServiceRegistration<TService>(componentRenderMode)));
39+
services.TryAddSingleton<RegisteredPersistentServiceRegistrationCollection>();
3940

4041
return services;
4142
}

src/Components/Components/test/PersistentState/PersistentServicesRegistryTest.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ public void ResolveRegistrations_RemovesDuplicateRegistrations()
260260
{
261261
// Arrange
262262
var serviceProvider = new ServiceCollection()
263+
.AddSingleton<RegisteredPersistentServiceRegistrationCollection>()
263264
.AddSingleton<IPersistentServiceRegistration>(new TestPersistentRegistration { Assembly = "Assembly1", FullTypeName = "Type1" })
264265
.AddSingleton<IPersistentServiceRegistration>(new TestPersistentRegistration { Assembly = "Assembly1", FullTypeName = "Type1" }) // Duplicate
265266
.AddSingleton<IPersistentServiceRegistration>(new TestPersistentRegistration { Assembly = "Assembly2", FullTypeName = "Type2" })

0 commit comments

Comments
 (0)