Skip to content

Commit a429ec3

Browse files
authored
Cache property intiailizers for the duration of component lifetime (#39450)
ComponentFactory is instantiated on a per-renderer basis. It has a cache that stores property initializers in a state independent way. In a Blazor server app, there is a HtmlRenderer created during pre-rendering and a per-circuit renderer which means we're calculating and allocating multiple copies of property intializers.
1 parent 968affa commit a429ec3

File tree

2 files changed

+5
-5
lines changed

2 files changed

+5
-5
lines changed

src/Components/Components/src/ComponentFactory.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ internal sealed class ComponentFactory
1414
private const BindingFlags _injectablePropertyBindingFlags
1515
= BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
1616

17-
private readonly ConcurrentDictionary<Type, Action<IServiceProvider, IComponent>> _cachedInitializers = new();
17+
private static readonly ConcurrentDictionary<Type, Action<IServiceProvider, IComponent>> _cachedInitializers = new();
1818

1919
private readonly IComponentActivator _componentActivator;
2020

@@ -23,7 +23,7 @@ public ComponentFactory(IComponentActivator componentActivator)
2323
_componentActivator = componentActivator ?? throw new ArgumentNullException(nameof(componentActivator));
2424
}
2525

26-
public void ClearCache() => _cachedInitializers.Clear();
26+
public static void ClearCache() => _cachedInitializers.Clear();
2727

2828
public IComponent InstantiateComponent(IServiceProvider serviceProvider, [DynamicallyAccessedMembers(Component)] Type componentType)
2929
{
@@ -38,7 +38,7 @@ public IComponent InstantiateComponent(IServiceProvider serviceProvider, [Dynami
3838
return component;
3939
}
4040

41-
private void PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
41+
private static void PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
4242
{
4343
// This is thread-safe because _cachedInitializers is a ConcurrentDictionary.
4444
// We might generate the initializer more than once for a given type, but would
@@ -53,7 +53,7 @@ private void PerformPropertyInjection(IServiceProvider serviceProvider, ICompone
5353
initializer(serviceProvider, instance);
5454
}
5555

56-
private Action<IServiceProvider, IComponent> CreateInitializer([DynamicallyAccessedMembers(Component)] Type type)
56+
private static Action<IServiceProvider, IComponent> CreateInitializer([DynamicallyAccessedMembers(Component)] Type type)
5757
{
5858
// Do all the reflection up front
5959
List<(string name, Type propertyType, PropertySetter setter)>? injectables = null;

src/Components/Components/src/RenderTree/Renderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private static IComponentActivator GetComponentActivatorOrDefault(IServiceProvid
129129
private async void RenderRootComponentsOnHotReload()
130130
{
131131
// Before re-rendering the root component, also clear any well-known caches in the framework
132-
_componentFactory.ClearCache();
132+
ComponentFactory.ClearCache();
133133
ComponentProperties.ClearCache();
134134
Routing.QueryParameterValueSupplier.ClearCache();
135135

0 commit comments

Comments
 (0)