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.Reflection;
using Microsoft.AspNetCore.Components.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Components
{
@ -25,7 +26,12 @@ namespace Microsoft.AspNetCore.Components
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))
{
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);
}
[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]
public void InstantiateComponent_AssignsPropertiesWithInjectAttribute()
{
@ -96,6 +122,15 @@ namespace Microsoft.AspNetCore.Components
.BuildServiceProvider();
}
private static IServiceProvider GetServiceProviderWithActivator()
{
return new ServiceCollection()
.AddTransient<TestService1>()
.AddTransient<TestService2>()
.AddSingleton<IComponentActivator, DefaultComponentActivator>()
.BuildServiceProvider();
}
private class EmptyComponent : IComponent
{
public void Attach(RenderHandle renderHandle)
@ -162,6 +197,8 @@ namespace Microsoft.AspNetCore.Components
public TestService2 Property5 { get; set; }
}
private class NonComponent { }
public class TestService1 { }
public class TestService2 { }
}

View File

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

View File

@ -212,12 +212,13 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddScoped<NavigationManager, HttpNavigationManager>();
services.TryAddScoped<IJSRuntime, UnsupportedJavaScriptRuntime>();
services.TryAddScoped<INavigationInterception, UnsupportedNavigationInterception>();
services.TryAddTransient<ControllerSaveTempDataPropertyFilter>();
// This does caching so it should stay singleton
services.TryAddSingleton<ITempDataProvider, CookieTempDataProvider>();
services.TryAddSingleton<TempDataSerializer, DefaultTempDataSerializer>();
services.TryAddSingleton<IComponentActivator, DefaultComponentActivator>();
//
// Antiforgery