diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 68e9684223..9e30893426 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -457,10 +457,8 @@ namespace Umbraco.Core () => PluginManager.ResolvePackageActions()); //the database migration objects - MigrationResolver.Current = new MigrationResolver( - Container, ProfilingLogger.Logger, - () => PluginManager.ResolveTypes()); - + MigrationCollectionBuilder.Register(Container) + .AddProducer(() => PluginManager.ResolveTypes()); // need to filter out the ones we dont want!! PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver( diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs index 19792047bf..59b92a31eb 100644 --- a/src/Umbraco.Core/DatabaseContext.cs +++ b/src/Umbraco.Core/DatabaseContext.cs @@ -428,7 +428,7 @@ namespace Umbraco.Core /// This assumes all of the previous checks are done! /// /// - internal Result UpgradeSchemaAndData(IMigrationEntryService migrationEntryService, IMigrationResolver migrationResolver) + internal Result UpgradeSchemaAndData(IMigrationEntryService migrationEntryService, MigrationCollectionBuilder builder) { try { @@ -487,7 +487,7 @@ namespace Umbraco.Core //DO the upgrade! - var runner = new MigrationRunner(migrationResolver, migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.GetSemanticVersion(), GlobalSettings.UmbracoMigrationName); + var runner = new MigrationRunner(builder, migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.GetSemanticVersion(), GlobalSettings.UmbracoMigrationName); var migrationContext = new MigrationContext(database, _logger); var upgraded = runner.Execute(migrationContext /*, true*/); diff --git a/src/Umbraco.Core/Persistence/Migrations/IMigrationCollectionBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/IMigrationCollectionBuilder.cs new file mode 100644 index 0000000000..b1c20f0e80 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/IMigrationCollectionBuilder.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Persistence.Migrations +{ + // exists so the builder can be mocked in tests + public interface IMigrationCollectionBuilder + { + MigrationCollection CreateCollection(IMigrationContext context); + } +} diff --git a/src/Umbraco.Core/Persistence/Migrations/IMigrationResolver.cs b/src/Umbraco.Core/Persistence/Migrations/IMigrationResolver.cs deleted file mode 100644 index 0f895a397b..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/IMigrationResolver.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Persistence.Migrations -{ - public interface IMigrationResolver - { - /// - /// Gets the migrations - /// - IEnumerable GetMigrations(IMigrationContext migrationContext); - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationCollection.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationCollection.cs new file mode 100644 index 0000000000..910eb62628 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationCollection.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Umbraco.Core.DependencyInjection; + +namespace Umbraco.Core.Persistence.Migrations +{ + public class MigrationCollection : BuilderCollectionBase + { + public MigrationCollection(IEnumerable items) + : base(items) + { } + } +} diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationCollectionBuilder.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationCollectionBuilder.cs new file mode 100644 index 0000000000..1b07bbbeba --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationCollectionBuilder.cs @@ -0,0 +1,37 @@ +using LightInject; +using Umbraco.Core.DependencyInjection; + +namespace Umbraco.Core.Persistence.Migrations +{ + public class MigrationCollectionBuilder : LazyCollectionBuilderBase, IMigrationCollectionBuilder + { + public MigrationCollectionBuilder(IServiceContainer container) + : base(container) + { + // because collection builders are "per container" this ctor should run only once per container. + // + // note: constructor dependencies do NOT work with lifetimes other than transient + // see https://github.com/seesharper/LightInject/issues/294 + // + // resolve ctor dependency from GetInstance() runtimeArguments, if possible - 'factory' is + // the container, 'info' describes the ctor argument, and 'args' contains the args that + // were passed to GetInstance() - use first arg if it is the right type. + // + // for IMigrationContext + container.RegisterConstructorDependency((factory, info, args) => args.Length > 0 ? args[0] as IMigrationContext : null); + + } + + protected override void Initialize() + { + // nothing - do not register the collection + } + + protected override MigrationCollectionBuilder This => this; + + public MigrationCollection CreateCollection(IMigrationContext context) + { + return new MigrationCollection(CreateItems(context)); + } + } +} diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationResolver.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationResolver.cs deleted file mode 100644 index 0512fe14c6..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationResolver.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using LightInject; -using Umbraco.Core.Logging; -using Umbraco.Core.ObjectResolution; - -namespace Umbraco.Core.Persistence.Migrations -{ - /// - /// A resolver to return all IMigrations - /// - internal class MigrationResolver : ContainerLazyManyObjectsResolver, IMigrationResolver - { - - public MigrationResolver(IServiceContainer container, ILogger logger, Func> migrations) - : base(container, logger, migrations, ObjectLifetimeScope.Transient) // do NOT change .Transient, see CreateValues below - { - } - - /// - /// This creates the instances in a child IoC container, everytime GetMigrations is called, a child container - /// is created, the types are added to it and resolved and the child container is diposed. - /// - /// - /// - /// - /// This doesn't need to be thread safe because Migration instances are transient anyways - /// - protected override IEnumerable CreateValues(ObjectLifetimeScope scope) - { - // note: constructor dependencies do NOT work with lifetimes other than transient - // see https://github.com/seesharper/LightInject/issues/294 - EnsureTypesRegisterred(scope, container => - { - // resolve ctor dependency from GetInstance() runtimeArguments, if possible - 'factory' is - // the container, 'info' describes the ctor argument, and 'args' contains the args that - // were passed to GetInstance() - use first arg if it is the right type, - // - // for IMigrationContext - container.RegisterConstructorDependency((factory, info, args) => args.Length > 0 ? args[0] as IMigrationContext : null); - }); - - var arg = new object[] { _migrationContext }; - return InstanceTypes.Select(x => (IMigration) Container.GetInstance(x, arg)); - } - - private IMigrationContext _migrationContext; - - /// - /// Gets the migrations - /// - public IEnumerable GetMigrations(IMigrationContext migrationContext) - { - //set the current context to use to create the values - _migrationContext = migrationContext; - - return Values; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs index 0bd4dc72f6..c333e676e7 100644 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Migrations /// public class MigrationRunner { - private readonly IMigrationResolver _resolver; + private readonly IMigrationCollectionBuilder _builder; private readonly IMigrationEntryService _migrationEntryService; private readonly ILogger _logger; private readonly SemVersion _currentVersion; @@ -30,16 +30,16 @@ namespace Umbraco.Core.Persistence.Migrations private readonly string _productName; private readonly IMigration[] _migrations; - public MigrationRunner(IMigrationResolver resolver, IMigrationEntryService migrationEntryService, ILogger logger, SemVersion currentVersion, SemVersion targetVersion, string productName, params IMigration[] migrations) + public MigrationRunner(IMigrationCollectionBuilder builder, IMigrationEntryService migrationEntryService, ILogger logger, SemVersion currentVersion, SemVersion targetVersion, string productName, params IMigration[] migrations) { - if (resolver == null) throw new ArgumentNullException("resolver"); + if (builder == null) throw new ArgumentNullException("builder"); if (migrationEntryService == null) throw new ArgumentNullException("migrationEntryService"); if (logger == null) throw new ArgumentNullException("logger"); if (currentVersion == null) throw new ArgumentNullException("currentVersion"); if (targetVersion == null) throw new ArgumentNullException("targetVersion"); Mandate.ParameterNotNullOrEmpty(productName, "productName"); - _resolver = resolver; + _builder = builder; _migrationEntryService = migrationEntryService; _logger = logger; _currentVersion = currentVersion; @@ -159,7 +159,7 @@ namespace Umbraco.Core.Persistence.Migrations protected IMigration[] FindMigrations(IMigrationContext context) { //MCH NOTE: Consider adding the ProductName filter to the Resolver so we don't get a bunch of irrelevant migrations - return _migrations ?? _resolver.GetMigrations(context).ToArray(); + return _migrations ?? _builder.CreateCollection(context).ToArray(); } internal void InitializeMigrations( diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0ffa875de1..809a135f87 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -271,6 +271,9 @@ + + + @@ -327,7 +330,6 @@ - @@ -823,7 +825,6 @@ - diff --git a/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs b/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs index 961f52c992..860c9e1ce9 100644 --- a/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs +++ b/src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs @@ -26,24 +26,19 @@ namespace Umbraco.Tests.Migrations [Test] public void Can_Find_Migrations_With_Target_Version_Six() { - var migrationResolver = new MigrationResolver( - Container, - Logger, - () => new List - { - typeof (AlterUserTableMigrationStub), - typeof(Dummy), - typeof (SixZeroMigration1), - typeof (SixZeroMigration2), - typeof (FourElevenMigration), - typeof (FiveZeroMigration) - }); + var builder = new MigrationCollectionBuilder(Container) + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(); var database = TestObjects.GetUmbracoSqlServerDatabase(Mock.Of()); var context = new MigrationContext(database, Logger); - var foundMigrations = migrationResolver.GetMigrations(context); + var foundMigrations = builder.CreateCollection(context); var targetVersion = new Version("6.0.0"); var list = new List(); diff --git a/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs b/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs index b97d3bcfb5..227fe1c47b 100644 --- a/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs @@ -111,7 +111,7 @@ namespace Umbraco.Tests.Migrations //Setup the MigrationRunner var migrationRunner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), logger, new SemVersion(7, 5, 0), diff --git a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs index 2f8bf511bd..016fcc5fe1 100644 --- a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs @@ -38,7 +38,7 @@ namespace Umbraco.Tests.Migrations public void Executes_Only_One_Migration_For_Spanning_Multiple_Targets() { var runner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), _logger, new SemVersion(4 /*, 0, 0*/), new SemVersion(6 /*, 0, 0*/), "Test"); @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Migrations public void Executes_Migration_For_Spanning_One_Target_1() { var runner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), _logger, new SemVersion(4 /*, 0, 0*/), new SemVersion(5 /*, 0, 0*/), "Test"); @@ -68,7 +68,7 @@ namespace Umbraco.Tests.Migrations public void Executes_Migration_For_Spanning_One_Target_2() { var runner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), _logger, new SemVersion(5, 0, 1), new SemVersion(6 /*, 0, 0*/), "Test"); diff --git a/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs b/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs index 30ee9b1298..d2035d498d 100644 --- a/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs +++ b/src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs @@ -23,8 +23,6 @@ namespace Umbraco.Tests.Migrations.Upgrades /// Regular expression that finds multiline block comments. private static readonly Regex FindComments = new Regex(@"\/\*.*?\*\/", RegexOptions.Singleline | RegexOptions.Compiled); - internal MigrationResolver MigrationResolver { get; private set; } - [SetUp] public virtual void Initialize() { @@ -60,7 +58,7 @@ namespace Umbraco.Tests.Migrations.Upgrades //Setup the MigrationRunner var migrationRunner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), logger, configuredVersion, diff --git a/src/Umbraco.Tests/Migrations/Upgrades/SqlCeDataUpgradeTest.cs b/src/Umbraco.Tests/Migrations/Upgrades/SqlCeDataUpgradeTest.cs index 7b1f7899ea..406f263d62 100644 --- a/src/Umbraco.Tests/Migrations/Upgrades/SqlCeDataUpgradeTest.cs +++ b/src/Umbraco.Tests/Migrations/Upgrades/SqlCeDataUpgradeTest.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.Migrations.Upgrades //Setup the MigrationRunner var migrationContext = new MigrationContext(db, Mock.Of()); var migrationRunner = new MigrationRunner( - Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of(), configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName); diff --git a/src/Umbraco.Tests/Persistence/Migrations/MigrationStartupHandlerTests.cs b/src/Umbraco.Tests/Persistence/Migrations/MigrationStartupHandlerTests.cs index 1f9ae3ac4f..5ee9f041fa 100644 --- a/src/Umbraco.Tests/Persistence/Migrations/MigrationStartupHandlerTests.cs +++ b/src/Umbraco.Tests/Persistence/Migrations/MigrationStartupHandlerTests.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Persistence.Migrations var db = TestObjects.GetUmbracoSqlCeDatabase(logger); var migrationContext = new MigrationContext(db, logger); - var runner1 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test1", + var runner1 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test1", new IMigration[] { Mock.Of() }); var result1 = runner1.Execute(migrationContext /*, false*/); Assert.AreEqual(1, changed1.CountExecuted); @@ -58,13 +58,13 @@ namespace Umbraco.Tests.Persistence.Migrations var db = TestObjects.GetUmbracoSqlCeDatabase(logger); var migrationContext = new MigrationContext(db, logger); - var runner1 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test1", + var runner1 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test1", new IMigration[] { Mock.Of()}); var result1 = runner1.Execute(migrationContext /*, false*/); Assert.AreEqual(1, changed1.CountExecuted); Assert.AreEqual(0, changed2.CountExecuted); - var runner2 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test2", + var runner2 = new MigrationRunner(Mock.Of(), Mock.Of(), logger, new SemVersion(1), new SemVersion(2), "Test2", new IMigration[] { Mock.Of() }); var result2 = runner2.Execute(migrationContext /*, false*/); Assert.AreEqual(1, changed1.CountExecuted); diff --git a/src/Umbraco.Web/Current.cs b/src/Umbraco.Web/Current.cs index f77159e819..4c3f1171c6 100644 --- a/src/Umbraco.Web/Current.cs +++ b/src/Umbraco.Web/Current.cs @@ -2,6 +2,7 @@ using LightInject; using Umbraco.Core.Cache; using Umbraco.Core.Events; +using Umbraco.Core.Persistence.Migrations; using Umbraco.Core.Strings; using Umbraco.Web.HealthCheck; using Umbraco.Web.PublishedCache; @@ -125,6 +126,9 @@ namespace Umbraco.Web public static ActionCollection Actions => Container.GetInstance(); + public static MigrationCollectionBuilder MigrationCollectionBuilder + => Container.GetInstance(); + #endregion #region Core Getters diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index b283b684dc..da2b9bbdaf 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.Install.InstallSteps var result = _applicationContext.DatabaseContext.UpgradeSchemaAndData( _applicationContext.Services.MigrationEntryService, - MigrationResolver.Current); + Current.MigrationCollectionBuilder); if (result.Success == false) {