From b822efc7d4103cb79c7ba6d7e1b33ee959b05b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Macanovi=C4=87?= Date: Fri, 6 Mar 2020 14:38:49 +0100 Subject: [PATCH 01/10] Add IComponentActivator --- .../src/Hosting/WebAssemblyHostBuilder.cs | 1 + .../Components/src/ComponentActivator.cs | 19 ++++++++++++++++++ .../Components/src/ComponentFactory.cs | 5 ++++- .../Components/src/IComponentActivator.cs | 20 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/Components/Components/src/ComponentActivator.cs create mode 100644 src/Components/Components/src/IComponentActivator.cs diff --git a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs index 7fa4dd0ae1ca..d5e9682168a0 100644 --- a/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs +++ b/src/Components/Blazor/Blazor/src/Hosting/WebAssemblyHostBuilder.cs @@ -94,6 +94,7 @@ private void CreateServiceProvider() services.AddSingleton(WebAssemblyNavigationManager.Instance); services.AddSingleton(WebAssemblyNavigationInterception.Instance); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(s => { // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/ComponentActivator.cs new file mode 100644 index 000000000000..9d0020dcd804 --- /dev/null +++ b/src/Components/Components/src/ComponentActivator.cs @@ -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 +{ + /// + /// Default implementation of component activator. + /// + public class ComponentActivator : IComponentActivator + { + /// + public object CreateInstance(Type componentType) + { + return Activator.CreateInstance( componentType ); + } + } +} diff --git a/src/Components/Components/src/ComponentFactory.cs b/src/Components/Components/src/ComponentFactory.cs index bf5de30d2a5d..f9367c3d7473 100644 --- a/src/Components/Components/src/ComponentFactory.cs +++ b/src/Components/Components/src/ComponentFactory.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Components.Reflection; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Components { @@ -25,7 +26,9 @@ private readonly ConcurrentDictionary public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType) { - var instance = Activator.CreateInstance(componentType); + var activator = serviceProvider.GetRequiredService(); + + var instance = activator.CreateInstance(componentType); if (!(instance is IComponent component)) { throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); diff --git a/src/Components/Components/src/IComponentActivator.cs b/src/Components/Components/src/IComponentActivator.cs new file mode 100644 index 000000000000..d0131f001e64 --- /dev/null +++ b/src/Components/Components/src/IComponentActivator.cs @@ -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 +{ + /// + /// Represents an activator that can be used to instantiate components. + /// + public interface IComponentActivator + { + /// + /// Creates an component of the specified type using that type's default constructor. + /// + /// The type of component to create. + /// A reference to the newly created component. + object CreateInstance(Type componentType); + } +} From 295a47761bd01d9e8914f5020eafed84b00e9fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Macanovi=C4=87?= Date: Fri, 6 Mar 2020 15:28:56 +0100 Subject: [PATCH 02/10] Added missing DI registrations for SSB --- .../DependencyInjection/ComponentServiceCollectionExtensions.cs | 1 + .../MvcViewFeaturesMvcCoreBuilderExtensions.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs b/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs index e906b7dc26fe..013ad6ecc4e9 100644 --- a/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs +++ b/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs @@ -74,6 +74,7 @@ public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollecti services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.TryAddEnumerable(ServiceDescriptor.Singleton, CircuitOptionsJSInteropDetailedErrorsConfiguration>()); diff --git a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 84ffe50ce1c2..b9156838ab40 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -212,6 +212,7 @@ internal static void AddViewServices(IServiceCollection services) services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); + services.TryAddScoped(); services.TryAddTransient(); From dba8a026bbfdda19de513bcac887ad13ad920560 Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Fri, 6 Mar 2020 22:16:39 +0100 Subject: [PATCH 03/10] Use default Activator if IComponentActivator is not specified in DI --- src/Components/Components/src/ComponentFactory.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Components/Components/src/ComponentFactory.cs b/src/Components/Components/src/ComponentFactory.cs index f9367c3d7473..3ba141834b3e 100644 --- a/src/Components/Components/src/ComponentFactory.cs +++ b/src/Components/Components/src/ComponentFactory.cs @@ -26,9 +26,12 @@ private readonly ConcurrentDictionary public IComponent InstantiateComponent(IServiceProvider serviceProvider, Type componentType) { - var activator = serviceProvider.GetRequiredService(); + var activator = serviceProvider.GetService(); + + var instance = activator != null + ? activator.CreateInstance(componentType) + : Activator.CreateInstance(componentType); - var instance = activator.CreateInstance(componentType); if (!(instance is IComponent component)) { throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); From e6f84fbcdf039ef1639d9f6aeeb81f72b6a18622 Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Tue, 30 Jun 2020 14:07:03 +0200 Subject: [PATCH 04/10] Rename ComponentActivator to DefaultComponentActivator --- src/Components/Components/src/ComponentActivator.cs | 2 +- .../DependencyInjection/ComponentServiceCollectionExtensions.cs | 2 +- .../MvcViewFeaturesMvcCoreBuilderExtensions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/ComponentActivator.cs index 9d0020dcd804..4501427b8f3d 100644 --- a/src/Components/Components/src/ComponentActivator.cs +++ b/src/Components/Components/src/ComponentActivator.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Components /// /// Default implementation of component activator. /// - public class ComponentActivator : IComponentActivator + public class DefaultComponentActivator : IComponentActivator { /// public object CreateInstance(Type componentType) diff --git a/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs b/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs index 857862db6da0..b8e66a4e5e8c 100644 --- a/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs +++ b/src/Components/Server/src/DependencyInjection/ComponentServiceCollectionExtensions.cs @@ -74,7 +74,7 @@ public static IServerSideBlazorBuilder AddServerSideBlazor(this IServiceCollecti services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.TryAddEnumerable(ServiceDescriptor.Singleton, CircuitOptionsJSInteropDetailedErrorsConfiguration>()); diff --git a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index b9156838ab40..096d2382da7e 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -212,7 +212,7 @@ internal static void AddViewServices(IServiceCollection services) services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); - services.TryAddScoped(); + services.TryAddScoped(); services.TryAddTransient(); From 29904537cc9eadbd4a966e7d3c4f848fcc144cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Macanovi=C4=87?= Date: Tue, 30 Jun 2020 14:10:13 +0200 Subject: [PATCH 05/10] Update src/Components/Components/src/ComponentActivator.cs Co-authored-by: Steve Sanderson --- src/Components/Components/src/ComponentActivator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/ComponentActivator.cs index 9d0020dcd804..754de9252c02 100644 --- a/src/Components/Components/src/ComponentActivator.cs +++ b/src/Components/Components/src/ComponentActivator.cs @@ -13,7 +13,7 @@ public class ComponentActivator : IComponentActivator /// public object CreateInstance(Type componentType) { - return Activator.CreateInstance( componentType ); + return Activator.CreateInstance(componentType); } } } From 469091b565581f5135c6d9019b3f102b9d880803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Macanovi=C4=87?= Date: Tue, 30 Jun 2020 14:10:56 +0200 Subject: [PATCH 06/10] Update src/Components/Components/src/ComponentActivator.cs Co-authored-by: Steve Sanderson --- src/Components/Components/src/ComponentActivator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/ComponentActivator.cs index 754de9252c02..b8f290267565 100644 --- a/src/Components/Components/src/ComponentActivator.cs +++ b/src/Components/Components/src/ComponentActivator.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Components public class ComponentActivator : IComponentActivator { /// - public object CreateInstance(Type componentType) + public IComponent CreateInstance(Type componentType) { return Activator.CreateInstance(componentType); } From 69cb2dc23d21b81303a8f4a882252327e37f55a9 Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Tue, 30 Jun 2020 15:20:15 +0200 Subject: [PATCH 07/10] IComponentActivator to return IComponent type --- src/Components/Components/src/ComponentActivator.cs | 4 ++-- src/Components/Components/src/IComponentActivator.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/ComponentActivator.cs index c1d36f46a145..4f93188f2f99 100644 --- a/src/Components/Components/src/ComponentActivator.cs +++ b/src/Components/Components/src/ComponentActivator.cs @@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Components public class DefaultComponentActivator : IComponentActivator { /// - public IComponent CreateInstance(Type componentType) + public IComponent? CreateInstance(Type componentType) { - return Activator.CreateInstance(componentType); + return Activator.CreateInstance(componentType) as IComponent; } } } diff --git a/src/Components/Components/src/IComponentActivator.cs b/src/Components/Components/src/IComponentActivator.cs index d0131f001e64..e98e111a05a4 100644 --- a/src/Components/Components/src/IComponentActivator.cs +++ b/src/Components/Components/src/IComponentActivator.cs @@ -15,6 +15,6 @@ public interface IComponentActivator /// /// The type of component to create. /// A reference to the newly created component. - object CreateInstance(Type componentType); + IComponent? CreateInstance(Type componentType); } } From 23e78d3225238befb4eeb97ad1c366ca1ea2da8a Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Tue, 30 Jun 2020 15:24:23 +0200 Subject: [PATCH 08/10] Register IComponentActivator as singleton --- .../MvcViewFeaturesMvcCoreBuilderExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 096d2382da7e..34b57eb37495 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -212,13 +212,13 @@ internal static void AddViewServices(IServiceCollection services) services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(); - services.TryAddScoped(); - + services.TryAddTransient(); // This does caching so it should stay singleton services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); // // Antiforgery From 160f45c45b9c55cb8fc20c0cabb9d9eb1996be85 Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Tue, 30 Jun 2020 15:26:08 +0200 Subject: [PATCH 09/10] Tests for default component activator --- .../Components/test/ComponentFactoryTest.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/Components/Components/test/ComponentFactoryTest.cs b/src/Components/Components/test/ComponentFactoryTest.cs index 4dd4de56e0ad..662351bd6f0e 100644 --- a/src/Components/Components/test/ComponentFactoryTest.cs +++ b/src/Components/Components/test/ComponentFactoryTest.cs @@ -27,6 +27,32 @@ public void InstantiateComponent_CreatesInstance() Assert.IsType(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(instance); + } + + [Fact] + public void InstantiateComponent_CreatesInstance_WithActivator_NonComponent() + { + // Arrange + var componentType = typeof(NonComponent); + var factory = new ComponentFactory(); + + // Assert + Assert.Throws(()=>factory.InstantiateComponent(GetServiceProviderWithActivator(), componentType)); + } + [Fact] public void InstantiateComponent_AssignsPropertiesWithInjectAttribute() { @@ -96,6 +122,15 @@ private static IServiceProvider GetServiceProvider() .BuildServiceProvider(); } + private static IServiceProvider GetServiceProviderWithActivator() + { + return new ServiceCollection() + .AddTransient() + .AddTransient() + .AddSingleton() + .BuildServiceProvider(); + } + private class EmptyComponent : IComponent { public void Attach(RenderHandle renderHandle) @@ -162,6 +197,8 @@ private class DerivedComponent : ComponentWithInjectProperties public TestService2 Property5 { get; set; } } + private class NonComponent { } + public class TestService1 { } public class TestService2 { } } From fcd0ac07f2292d937e4f1a73514695fe84147638 Mon Sep 17 00:00:00 2001 From: Mladen Macanovic Date: Thu, 2 Jul 2020 14:02:23 +0200 Subject: [PATCH 10/10] Rename ComponentActivator file to DefaultComponentActivator --- .../src/{ComponentActivator.cs => DefaultComponentActivator.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Components/Components/src/{ComponentActivator.cs => DefaultComponentActivator.cs} (100%) diff --git a/src/Components/Components/src/ComponentActivator.cs b/src/Components/Components/src/DefaultComponentActivator.cs similarity index 100% rename from src/Components/Components/src/ComponentActivator.cs rename to src/Components/Components/src/DefaultComponentActivator.cs