Skip to content

Commit dae55ed

Browse files
stsrkiSteveSandersonMS
authored andcommitted
Add IComponentActivator
1 parent 156023d commit dae55ed

File tree

6 files changed

+86
-2
lines changed

6 files changed

+86
-2
lines changed

src/Components/Components/src/ComponentFactory.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Linq;
77
using System.Reflection;
88
using Microsoft.AspNetCore.Components.Reflection;
9+
using Microsoft.Extensions.DependencyInjection;
910

1011
namespace Microsoft.AspNetCore.Components
1112
{
@@ -25,7 +26,12 @@ private readonly ConcurrentDictionary<Type, Action<IServiceProvider, IComponent>
2526

2627
public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
2728
{
28-
var instance = Activator.CreateInstance(componentType);
29+
var activator = serviceProvider.GetService<IComponentActivator>();
30+
31+
var instance = activator != null
32+
? activator.CreateInstance(componentType)
33+
: Activator.CreateInstance(componentType);
34+
2935
if (!(instance is IComponent component))
3036
{
3137
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType));
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Components
7+
{
8+
/// <summary>
9+
/// Default implementation of component activator.
10+
/// </summary>
11+
public class DefaultComponentActivator : IComponentActivator
12+
{
13+
/// <inheritdoc />
14+
public IComponent? CreateInstance(Type componentType)
15+
{
16+
return Activator.CreateInstance(componentType) as IComponent;
17+
}
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNetCore.Components
7+
{
8+
/// <summary>
9+
/// Represents an activator that can be used to instantiate components.
10+
/// </summary>
11+
public interface IComponentActivator
12+
{
13+
/// <summary>
14+
/// Creates an component of the specified type using that type's default constructor.
15+
/// </summary>
16+
/// <param name="componentType">The type of component to create.</param>
17+
/// <returns>A reference to the newly created component.</returns>
18+
IComponent? CreateInstance(Type componentType);
19+
}
20+
}

src/Components/Components/test/ComponentFactoryTest.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,32 @@ public void InstantiateComponent_CreatesInstance()
2727
Assert.IsType<EmptyComponent>(instance);
2828
}
2929

30+
[Fact]
31+
public void InstantiateComponent_CreatesInstance_WithActivator()
32+
{
33+
// Arrange
34+
var componentType = typeof(EmptyComponent);
35+
var factory = new ComponentFactory();
36+
37+
// Act
38+
var instance = factory.InstantiateComponent(GetServiceProviderWithActivator(), componentType);
39+
40+
// Assert
41+
Assert.NotNull(instance);
42+
Assert.IsType<EmptyComponent>(instance);
43+
}
44+
45+
[Fact]
46+
public void InstantiateComponent_CreatesInstance_WithActivator_NonComponent()
47+
{
48+
// Arrange
49+
var componentType = typeof(NonComponent);
50+
var factory = new ComponentFactory();
51+
52+
// Assert
53+
Assert.Throws<ArgumentException>(()=>factory.InstantiateComponent(GetServiceProviderWithActivator(), componentType));
54+
}
55+
3056
[Fact]
3157
public void InstantiateComponent_AssignsPropertiesWithInjectAttribute()
3258
{
@@ -96,6 +122,15 @@ private static IServiceProvider GetServiceProvider()
96122
.BuildServiceProvider();
97123
}
98124

125+
private static IServiceProvider GetServiceProviderWithActivator()
126+
{
127+
return new ServiceCollection()
128+
.AddTransient<TestService1>()
129+
.AddTransient<TestService2>()
130+
.AddSingleton<IComponentActivator, DefaultComponentActivator>()
131+
.BuildServiceProvider();
132+
}
133+
99134
private class EmptyComponent : IComponent
100135
{
101136
public void Attach(RenderHandle renderHandle)
@@ -162,6 +197,8 @@ private class DerivedComponent : ComponentWithInjectProperties
162197
public TestService2 Property5 { get; set; }
163198
}
164199

200+
private class NonComponent { }
201+
165202
public class TestService1 { }
166203
public class TestService2 { }
167204
}

src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollecti
7474
services.AddScoped<IJSRuntime, RemoteJSRuntime>();
7575
services.AddScoped<INavigationInterception, RemoteNavigationInterception>();
7676
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
77+
services.AddScoped<IComponentActivator, DefaultComponentActivator>();
7778

7879
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJSInteropDetailedErrorsConfiguration>());
7980

src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,13 @@ internal static void AddViewServices(IServiceCollection services)
212212
services.TryAddScoped<NavigationManager, HttpNavigationManager>();
213213
services.TryAddScoped<IJSRuntime, UnsupportedJavaScriptRuntime>();
214214
services.TryAddScoped<INavigationInterception, UnsupportedNavigationInterception>();
215-
215+
216216
services.TryAddTransient<ControllerSaveTempDataPropertyFilter>();
217217

218218
// This does caching so it should stay singleton
219219
services.TryAddSingleton<ITempDataProvider, CookieTempDataProvider>();
220220
services.TryAddSingleton<TempDataSerializer, DefaultTempDataSerializer>();
221+
services.TryAddSingleton<IComponentActivator, DefaultComponentActivator>();
221222

222223
//
223224
// Antiforgery

0 commit comments

Comments
 (0)