Add IComponentActivator

This commit is contained in:
Mladen Macanović 2020-03-06 14:38:49 +01:00 committed by Steve Sanderson
parent 156023d3f9
commit dae55edfec
6 changed files with 86 additions and 2 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Components.Reflection; using Microsoft.AspNetCore.Components.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Components namespace Microsoft.AspNetCore.Components
{ {
@ -25,7 +26,12 @@ namespace Microsoft.AspNetCore.Components
public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType) public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
{ {
var instance = Activator.CreateInstance(componentType); var activator = serviceProvider.GetService<IComponentActivator>();
var instance = activator != null
? activator.CreateInstance(componentType)
: Activator.CreateInstance(componentType);
if (!(instance is IComponent component)) if (!(instance is IComponent component))
{ {
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType));

View File

@ -0,0 +1,19 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Components
{
/// <summary>
/// Default implementation of component activator.
/// </summary>
public class DefaultComponentActivator : IComponentActivator
{
/// <inheritdoc />
public IComponent? CreateInstance(Type componentType)
{
return Activator.CreateInstance(componentType) as IComponent;
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Components
{
/// <summary>
/// Represents an activator that can be used to instantiate components.
/// </summary>
public interface IComponentActivator
{
/// <summary>
/// Creates an component of the specified type using that type's default constructor.
/// </summary>
/// <param name="componentType">The type of component to create.</param>
/// <returns>A reference to the newly created component.</returns>
IComponent? CreateInstance(Type componentType);
}
}

View File

@ -27,6 +27,32 @@ namespace Microsoft.AspNetCore.Components
Assert.IsType<EmptyComponent>(instance); Assert.IsType<EmptyComponent>(instance);
} }
[Fact]
public void InstantiateComponent_CreatesInstance_WithActivator()
{
// Arrange
var componentType = typeof(EmptyComponent);
var factory = new ComponentFactory();
// Act
var instance = factory.InstantiateComponent(GetServiceProviderWithActivator(), componentType);
// Assert
Assert.NotNull(instance);
Assert.IsType<EmptyComponent>(instance);
}
[Fact]
public void InstantiateComponent_CreatesInstance_WithActivator_NonComponent()
{
// Arrange
var componentType = typeof(NonComponent);
var factory = new ComponentFactory();
// Assert
Assert.Throws<ArgumentException>(()=>factory.InstantiateComponent(GetServiceProviderWithActivator(), componentType));
}
[Fact] [Fact]
public void InstantiateComponent_AssignsPropertiesWithInjectAttribute() public void InstantiateComponent_AssignsPropertiesWithInjectAttribute()
{ {
@ -96,6 +122,15 @@ namespace Microsoft.AspNetCore.Components
.BuildServiceProvider(); .BuildServiceProvider();
} }
private static IServiceProvider GetServiceProviderWithActivator()
{
return new ServiceCollection()
.AddTransient<TestService1>()
.AddTransient<TestService2>()
.AddSingleton<IComponentActivator, DefaultComponentActivator>()
.BuildServiceProvider();
}
private class EmptyComponent : IComponent private class EmptyComponent : IComponent
{ {
public void Attach(RenderHandle renderHandle) public void Attach(RenderHandle renderHandle)
@ -162,6 +197,8 @@ namespace Microsoft.AspNetCore.Components
public TestService2 Property5 { get; set; } public TestService2 Property5 { get; set; }
} }
private class NonComponent { }
public class TestService1 { } public class TestService1 { }
public class TestService2 { } public class TestService2 { }
} }

View File

@ -74,6 +74,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddScoped<IJSRuntime, RemoteJSRuntime>(); services.AddScoped<IJSRuntime, RemoteJSRuntime>();
services.AddScoped<INavigationInterception, RemoteNavigationInterception>(); services.AddScoped<INavigationInterception, RemoteNavigationInterception>();
services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>(); services.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>();
services.AddScoped<IComponentActivator, DefaultComponentActivator>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJSInteropDetailedErrorsConfiguration>()); services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<CircuitOptions>, CircuitOptionsJSInteropDetailedErrorsConfiguration>());

View File

@ -218,6 +218,7 @@ namespace Microsoft.Extensions.DependencyInjection
// This does caching so it should stay singleton // This does caching so it should stay singleton
services.TryAddSingleton<ITempDataProvider, CookieTempDataProvider>(); services.TryAddSingleton<ITempDataProvider, CookieTempDataProvider>();
services.TryAddSingleton<TempDataSerializer, DefaultTempDataSerializer>(); services.TryAddSingleton<TempDataSerializer, DefaultTempDataSerializer>();
services.TryAddSingleton<IComponentActivator, DefaultComponentActivator>();
// //
// Antiforgery // Antiforgery