From bc80affcf1e11894660d0614eee1c709e809fe18 Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Sun, 2 Sep 2018 22:09:37 +0200 Subject: [PATCH] Dictionary params & error handling --- .../Composing/ContainerExtensions.cs | 23 ++++++++++++++++--- src/Umbraco.Core/Composing/IContainer.cs | 9 ++++++-- .../LightInject/LightInjectContainer.cs | 22 ++++++++++++++++-- src/Umbraco.Core/IO/FileSystems.cs | 2 +- .../Migrations/MigrationBuilder.cs | 3 ++- .../Composing/ContainerImplementationTests.cs | 5 ++-- src/Umbraco.Web/Composing/ModuleInjector.cs | 20 ++++++++++++---- 7 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/Composing/ContainerExtensions.cs b/src/Umbraco.Core/Composing/ContainerExtensions.cs index 423af98691..5d839c9c8e 100644 --- a/src/Umbraco.Core/Composing/ContainerExtensions.cs +++ b/src/Umbraco.Core/Composing/ContainerExtensions.cs @@ -19,6 +19,17 @@ namespace Umbraco.Core.Composing public static T GetInstance(this IContainer container) => (T) container.GetInstance(typeof(T)); + /// + /// Gets a named instance. + /// + /// The type of the instance. + /// The container. + /// The name of the instance. + /// An instance of the specified type and name. + /// Throws an exception if the container failed to get an instance of the specified type. + public static T GetInstance(this IContainer container, string name) + => (T) container.GetInstance(typeof(T), name); + /// /// Tries to get an instance. /// @@ -49,7 +60,7 @@ namespace Umbraco.Core.Composing /// Throws an exception if the container failed to get an instance of the specified type. /// The arguments are used as dependencies by the container. /// - public static T CreateInstance(this IContainer container, params object[] args) + public static T CreateInstance(this IContainer container, IDictionary args) => (T) container.CreateInstance(typeof(T), args); /// @@ -64,6 +75,12 @@ namespace Umbraco.Core.Composing public static void Register(this IContainer container, string name, Lifetime lifetime = Lifetime.Transient) => container.Register(typeof(TService), typeof(TImplementing), name, lifetime); + /// + /// Registers a service with a named implementation type and factory. + /// + public static void Register(this IContainer container, string name, Func factory, Lifetime lifetime = Lifetime.Transient) + => container.Register(factory, name, lifetime); + /// /// Registers a service as its own implementation. /// @@ -112,8 +129,8 @@ namespace Umbraco.Core.Composing if (container.GetRegistered().Any()) throw new InvalidOperationException("Collection builders should be registered only once."); - // register the builder - passing the container as an arg to the factory - container.RegisterSingleton(c => c.CreateInstance(container)); + // register the builder + container.RegisterSingleton(); // initialize and return the builder return container.GetInstance(); diff --git a/src/Umbraco.Core/Composing/IContainer.cs b/src/Umbraco.Core/Composing/IContainer.cs index dab5dd159c..9a5452bf65 100644 --- a/src/Umbraco.Core/Composing/IContainer.cs +++ b/src/Umbraco.Core/Composing/IContainer.cs @@ -70,14 +70,14 @@ namespace Umbraco.Core.Composing /// Creates an instance with arguments. /// /// The type of the instance. - /// Arguments. + /// Named arguments. /// An instance of the specified type. /// /// The instance type does not need to be registered into the container. /// The arguments are used as dependencies by the container. Other dependencies /// are retrieved from the container. /// - object CreateInstance(Type type, params object[] args); + object CreateInstance(Type type, IDictionary args); #endregion @@ -104,6 +104,11 @@ namespace Umbraco.Core.Composing /// void Register(Type serviceType, Type implementingType, string name, Lifetime lifetime = Lifetime.Transient); + /// + /// Registers a named service with an implementation factory. + /// + void Register(Func factory, string name, Lifetime lifetime = Lifetime.Transient); + /// /// Registers a service with an implementation factory. /// diff --git a/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs b/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs index ecb8f0a460..f9dd0028b2 100644 --- a/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs +++ b/src/Umbraco.Core/Composing/LightInject/LightInjectContainer.cs @@ -126,7 +126,7 @@ namespace Umbraco.Core.Composing.LightInject => Container.AvailableServices.Where(x => x.ServiceType == type).Select(x => new Registration(x.ServiceType, x.ServiceName)); /// - public object CreateInstance(Type type, params object[] args) + public object CreateInstance(Type type, IDictionary args) { // LightInject has this, but then it requires RegisterConstructorDependency etc and has various oddities // including the most annoying one, which is that it does not work on singletons (hard to fix) @@ -146,7 +146,7 @@ namespace Umbraco.Core.Composing.LightInject { // no! IsInstanceOfType is not ok here // ReSharper disable once UseMethodIsInstanceOfType - var arg = args?.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); + var arg = args?.Values.FirstOrDefault(a => parameter.ParameterType.IsAssignableFrom(a.GetType())); ctorArgs[i++] = arg ?? GetInstance(parameter.ParameterType); } return ctor.Invoke(ctorArgs); @@ -234,6 +234,24 @@ namespace Umbraco.Core.Composing.LightInject } } + /// + public void Register(Func factory, string name, Lifetime lifetime = Lifetime.Transient) + { + switch (lifetime) + { + case Lifetime.Transient: + case Lifetime.Request: + case Lifetime.Scope: + Container.Register(f => factory(this), name, GetLifetime(lifetime)); + break; + case Lifetime.Singleton: + Container.RegisterSingleton(f => factory(this), name); + break; + default: + throw new NotSupportedException($"Lifetime {lifetime} is not supported."); + } + } + private ILifetime GetLifetime(Lifetime lifetime) { switch (lifetime) diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index 5a4ee92e15..43ac94624e 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -299,7 +299,7 @@ namespace Umbraco.Core.IO var shadowWrapper = new ShadowWrapper(innerFs, "typed/" + alias, () => IsScoped()); // getting the fs from the container - see FileSystemsComposer - var fs = Current.Container.CreateInstance((IFileSystem) shadowWrapper); + var fs = Current.Container.CreateInstance(new Dictionary{{ "wrapped", (IFileSystem) shadowWrapper }}); _wrappers.Add(shadowWrapper); // keeping a reference to the wrapper return fs; }); diff --git a/src/Umbraco.Core/Migrations/MigrationBuilder.cs b/src/Umbraco.Core/Migrations/MigrationBuilder.cs index aebd8bd1ee..65e40f6e75 100644 --- a/src/Umbraco.Core/Migrations/MigrationBuilder.cs +++ b/src/Umbraco.Core/Migrations/MigrationBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Umbraco.Core.Composing; namespace Umbraco.Core.Migrations @@ -14,7 +15,7 @@ namespace Umbraco.Core.Migrations public IMigration Build(Type migrationType, IMigrationContext context) { - return (IMigration) _container.CreateInstance(migrationType, context); + return (IMigration) _container.CreateInstance(migrationType, new Dictionary{{"context", context}}); } } } diff --git a/src/Umbraco.Tests/Composing/ContainerImplementationTests.cs b/src/Umbraco.Tests/Composing/ContainerImplementationTests.cs index 818bf47cd0..f16c6534fc 100644 --- a/src/Umbraco.Tests/Composing/ContainerImplementationTests.cs +++ b/src/Umbraco.Tests/Composing/ContainerImplementationTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using System.Collections.Generic; +using NUnit.Framework; using Umbraco.Core.Composing; namespace Umbraco.Tests.Composing @@ -46,7 +47,7 @@ namespace Umbraco.Tests.Composing public void CanRegisterSingletonWithCreate() { var container = CreateContainer(); - container.RegisterSingleton(c => c.CreateInstance(new TestClass1())); + container.RegisterSingleton(c => c.CreateInstance(new Dictionary{{"c", new TestClass1()}})); var s1 = container.GetInstance(); var s2 = container.GetInstance(); Assert.AreSame(s1, s2); diff --git a/src/Umbraco.Web/Composing/ModuleInjector.cs b/src/Umbraco.Web/Composing/ModuleInjector.cs index 5938a8060a..8ff8f407e1 100644 --- a/src/Umbraco.Web/Composing/ModuleInjector.cs +++ b/src/Umbraco.Web/Composing/ModuleInjector.cs @@ -1,4 +1,5 @@ -using System.Web; +using System; +using System.Web; using Umbraco.Core; using Umbraco.Core.Composing; @@ -16,9 +17,20 @@ namespace Umbraco.Web.Composing /// public void Init(HttpApplication context) { - // using the service locator here - no other way, really - Module = Current.Container.GetInstance(); - Module.Init(context); + try + { + // using the service locator here - no other way, really + Module = Current.Container.GetInstance(); + Module.Init(context); + } + catch + { + var runtimeState = Current.Container.GetInstance(); + if (runtimeState.BootFailedException != null) + { + throw new Exception("Failed to boot", runtimeState.BootFailedException); + } + } } ///