Resvolution - MigrationResolver

This commit is contained in:
Stephan
2016-08-13 12:51:22 +02:00
parent bbd632f644
commit e49a3f4c72
17 changed files with 91 additions and 111 deletions

View File

@@ -457,10 +457,8 @@ namespace Umbraco.Core
() => PluginManager.ResolvePackageActions());
//the database migration objects
MigrationResolver.Current = new MigrationResolver(
Container, ProfilingLogger.Logger,
() => PluginManager.ResolveTypes<IMigration>());
MigrationCollectionBuilder.Register(Container)
.AddProducer(() => PluginManager.ResolveTypes<IMigration>());
// need to filter out the ones we dont want!!
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(

View File

@@ -428,7 +428,7 @@ namespace Umbraco.Core
/// This assumes all of the previous checks are done!
/// </summary>
/// <returns></returns>
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*/);

View File

@@ -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);
}
}

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Persistence.Migrations
{
public interface IMigrationResolver
{
/// <summary>
/// Gets the migrations
/// </summary>
IEnumerable<IMigration> GetMigrations(IMigrationContext migrationContext);
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using Umbraco.Core.DependencyInjection;
namespace Umbraco.Core.Persistence.Migrations
{
public class MigrationCollection : BuilderCollectionBase<IMigration>
{
public MigrationCollection(IEnumerable<IMigration> items)
: base(items)
{ }
}
}

View File

@@ -0,0 +1,37 @@
using LightInject;
using Umbraco.Core.DependencyInjection;
namespace Umbraco.Core.Persistence.Migrations
{
public class MigrationCollectionBuilder : LazyCollectionBuilderBase<MigrationCollectionBuilder, MigrationCollection, IMigration>, 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));
}
}
}

View File

@@ -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
{
/// <summary>
/// A resolver to return all IMigrations
/// </summary>
internal class MigrationResolver : ContainerLazyManyObjectsResolver<MigrationResolver, IMigration>, IMigrationResolver
{
public MigrationResolver(IServiceContainer container, ILogger logger, Func<IEnumerable<Type>> migrations)
: base(container, logger, migrations, ObjectLifetimeScope.Transient) // do NOT change .Transient, see CreateValues below
{
}
/// <summary>
/// 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.
/// </summary>
/// <param name="scope"></param>
/// <returns></returns>
/// <remarks>
/// This doesn't need to be thread safe because Migration instances are transient anyways
/// </remarks>
protected override IEnumerable<IMigration> 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;
/// <summary>
/// Gets the migrations
/// </summary>
public IEnumerable<IMigration> GetMigrations(IMigrationContext migrationContext)
{
//set the current context to use to create the values
_migrationContext = migrationContext;
return Values;
}
}
}

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Migrations
/// </summary>
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(

View File

@@ -271,6 +271,9 @@
<Compile Include="Models\PublishedContent\PropertyResult.cs" />
<Compile Include="Models\PublishedContent\PropertyResultType.cs" />
<Compile Include="Persistence\IUmbracoDatabaseAccessor.cs" />
<Compile Include="Persistence\Migrations\IMigrationCollectionBuilder.cs" />
<Compile Include="Persistence\Migrations\MigrationCollection.cs" />
<Compile Include="Persistence\Migrations\MigrationCollectionBuilder.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\AddContentNuTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\RefactorXmlColumns.cs" />
<Compile Include="Persistence\ThreadStaticUmbracoDatabaseAccessor.cs" />
@@ -327,7 +330,6 @@
<Compile Include="Persistence\UnitOfWorkExtensions.cs" />
<Compile Include="Persistence\Mappers\AuditItemMapper.cs" />
<Compile Include="Persistence\Mappers\IMappingResolver.cs" />
<Compile Include="Persistence\Migrations\IMigrationResolver.cs" />
<Compile Include="Persistence\NPocoDatabaseTypeExtensions.cs" />
<Compile Include="Persistence\Querying\IQueryFactory.cs" />
<Compile Include="Persistence\Querying\QueryFactory.cs" />
@@ -823,7 +825,6 @@
<Compile Include="Persistence\Migrations\MigrationBase.cs" />
<Compile Include="Persistence\Migrations\MigrationContext.cs" />
<Compile Include="Persistence\Migrations\MigrationExpressionBase.cs" />
<Compile Include="Persistence\Migrations\MigrationResolver.cs" />
<Compile Include="Persistence\Migrations\MigrationRunner.cs" />
<Compile Include="Persistence\Migrations\Syntax\Alter\AlterSyntaxBuilder.cs" />
<Compile Include="Persistence\Migrations\Syntax\Alter\Column\AlterColumnBuilder.cs" />

View File

@@ -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<Type>
{
typeof (AlterUserTableMigrationStub),
typeof(Dummy),
typeof (SixZeroMigration1),
typeof (SixZeroMigration2),
typeof (FourElevenMigration),
typeof (FiveZeroMigration)
});
var builder = new MigrationCollectionBuilder(Container)
.Add<AlterUserTableMigrationStub>()
.Add<Dummy>()
.Add<SixZeroMigration1>()
.Add<SixZeroMigration2>()
.Add<FourElevenMigration>()
.Add<FiveZeroMigration>();
var database = TestObjects.GetUmbracoSqlServerDatabase(Mock.Of<ILogger>());
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<IMigration>();

View File

@@ -111,7 +111,7 @@ namespace Umbraco.Tests.Migrations
//Setup the MigrationRunner
var migrationRunner = new MigrationRunner(
Mock.Of<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
logger,
new SemVersion(7, 5, 0),

View File

@@ -38,7 +38,7 @@ namespace Umbraco.Tests.Migrations
public void Executes_Only_One_Migration_For_Spanning_Multiple_Targets()
{
var runner = new MigrationRunner(
Mock.Of<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
_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<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
_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<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
_logger, new SemVersion(5, 0, 1), new SemVersion(6 /*, 0, 0*/), "Test");

View File

@@ -23,8 +23,6 @@ namespace Umbraco.Tests.Migrations.Upgrades
/// <summary>Regular expression that finds multiline block comments.</summary>
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<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
logger,
configuredVersion,

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
//Setup the MigrationRunner
var migrationContext = new MigrationContext(db, Mock.Of<ILogger>());
var migrationRunner = new MigrationRunner(
Mock.Of<IMigrationResolver>(),
Mock.Of<IMigrationCollectionBuilder>(),
Mock.Of<IMigrationEntryService>(),
Mock.Of<ILogger>(), configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);

View File

@@ -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<IMigrationResolver>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test1",
var runner1 = new MigrationRunner(Mock.Of<IMigrationCollectionBuilder>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test1",
new IMigration[] { Mock.Of<IMigration>() });
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<IMigrationResolver>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test1",
var runner1 = new MigrationRunner(Mock.Of<IMigrationCollectionBuilder>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test1",
new IMigration[] { Mock.Of<IMigration>()});
var result1 = runner1.Execute(migrationContext /*, false*/);
Assert.AreEqual(1, changed1.CountExecuted);
Assert.AreEqual(0, changed2.CountExecuted);
var runner2 = new MigrationRunner(Mock.Of<IMigrationResolver>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test2",
var runner2 = new MigrationRunner(Mock.Of<IMigrationCollectionBuilder>(), Mock.Of<IMigrationEntryService>(), logger, new SemVersion(1), new SemVersion(2), "Test2",
new IMigration[] { Mock.Of<IMigration>() });
var result2 = runner2.Execute(migrationContext /*, false*/);
Assert.AreEqual(1, changed1.CountExecuted);

View File

@@ -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<ActionCollection>();
public static MigrationCollectionBuilder MigrationCollectionBuilder
=> Container.GetInstance<MigrationCollectionBuilder>();
#endregion
#region Core Getters

View File

@@ -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)
{