diff --git a/src/Umbraco.Core/Components/CompositionExtensions.cs b/src/Umbraco.Core/Components/CompositionExtensions.cs index 8810213421..96d7e7d5c7 100644 --- a/src/Umbraco.Core/Components/CompositionExtensions.cs +++ b/src/Umbraco.Core/Components/CompositionExtensions.cs @@ -110,13 +110,6 @@ namespace Umbraco.Core.Components internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition) => composition.WithCollectionBuilder(); - /// - /// Gets the post-migrations collection builder. - /// - /// The composition. - internal static PostMigrationCollectionBuilder PostMigrations(this Composition composition) - => composition.WithCollectionBuilder(); - /// /// Gets the components collection builder. /// diff --git a/src/Umbraco.Core/Migrations/IMigrationContext.cs b/src/Umbraco.Core/Migrations/IMigrationContext.cs index 80ba78b6de..8ac464e914 100644 --- a/src/Umbraco.Core/Migrations/IMigrationContext.cs +++ b/src/Umbraco.Core/Migrations/IMigrationContext.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Logging; +using System; +using System.Collections.Generic; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations @@ -32,5 +34,13 @@ namespace Umbraco.Core.Migrations /// Gets or sets a value indicating whether an expression is being built. /// bool BuildingExpression { get; set; } + + /// + /// Gets the post-migrations. + /// + /// + /// Types in this must implement . + /// + List PostMigrations { get; } } } diff --git a/src/Umbraco.Core/Migrations/IPostMigration.cs b/src/Umbraco.Core/Migrations/IPostMigration.cs deleted file mode 100644 index 15daf0fc74..0000000000 --- a/src/Umbraco.Core/Migrations/IPostMigration.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Semver; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; - -namespace Umbraco.Core.Migrations -{ - public interface IPostMigration : IDiscoverable - { - void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger); - } -} diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index 9c6ff208f8..5c4defab0c 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -27,7 +27,6 @@ namespace Umbraco.Core.Migrations.Install private readonly IRuntimeState _runtime; private readonly IMigrationBuilder _migrationBuilder; private readonly IKeyValueService _keyValueService; - private readonly PostMigrationCollection _postMigrations; private readonly ILogger _logger; private DatabaseSchemaResult _databaseSchemaValidationResult; @@ -35,7 +34,7 @@ namespace Umbraco.Core.Migrations.Install /// /// Initializes a new instance of the class. /// - public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) + public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService) { _scopeProvider = scopeProvider; _globalSettings = globalSettings; @@ -44,7 +43,6 @@ namespace Umbraco.Core.Migrations.Install _logger = logger; _migrationBuilder = migrationBuilder; _keyValueService = keyValueService; - _postMigrations = postMigrations; } #region Status @@ -483,7 +481,7 @@ namespace Umbraco.Core.Migrations.Install /// configured and it is possible to connect to the database. /// Runs whichever migrations need to run. /// - public Result UpgradeSchemaAndData() + public Result UpgradeSchemaAndData(MigrationPlan plan) { try { @@ -496,8 +494,8 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database upgrade started"); // upgrade - var upgrader = new UmbracoUpgrader(); - upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations); + var upgrader = new Upgrader(plan); + upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger); var message = "

Upgrade completed!

"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 7f7229ccd6..1fefcf85d9 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -321,7 +321,7 @@ namespace Umbraco.Core.Migrations.Install { // on install, initialize the umbraco migration plan with the final state - var upgrader = new UmbracoUpgrader(); + var upgrader = new Upgrader(new UmbracoPlan()); var stateValueKey = upgrader.StateValueKey; var finalState = upgrader.Plan.FinalState; diff --git a/src/Umbraco.Core/Migrations/MigrationContext.cs b/src/Umbraco.Core/Migrations/MigrationContext.cs index da454fab03..a43213cd31 100644 --- a/src/Umbraco.Core/Migrations/MigrationContext.cs +++ b/src/Umbraco.Core/Migrations/MigrationContext.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations { /// - /// Represents a migration context. + /// Implements . /// internal class MigrationContext : IMigrationContext { @@ -32,5 +33,8 @@ namespace Umbraco.Core.Migrations /// public bool BuildingExpression { get; set; } + + /// + public List PostMigrations { get; } = new List(); } } diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 9ede9f04f2..a3778c8cca 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -14,6 +14,7 @@ namespace Umbraco.Core.Migrations public class MigrationPlan { private readonly Dictionary _transitions = new Dictionary(); + private readonly List _postMigrationTypes = new List(); private string _prevState; private string _finalState; @@ -166,6 +167,25 @@ namespace Umbraco.Core.Migrations return this; } + /// + /// Prepares post-migrations. + /// + /// + /// This can be overriden to filter, complement, and/or re-order post-migrations. + /// + protected virtual IEnumerable PreparePostMigrations(IEnumerable types) + => types; + + /// + /// Adds a post-migration to the plan. + /// + public virtual MigrationPlan AddPostMigration() + where TMigration : IMigration + { + _postMigrationTypes.Add(typeof(TMigration)); + return this; + } + /// /// Creates a random, unique state. /// @@ -270,6 +290,7 @@ namespace Umbraco.Core.Migrations throw new Exception($"Unknown state \"{origState}\"."); var context = new MigrationContext(scope.Database, logger); + context.PostMigrations.AddRange(_postMigrationTypes); while (transition != null) { @@ -285,6 +306,26 @@ namespace Umbraco.Core.Migrations throw new Exception($"Unknown state \"{origState}\"."); } + // prepare and de-duplicate post-migrations, only keeping the 1st occurence + bool EnsureMigrationType(Type type) + { + if (!typeof(IMigration).IsAssignableFrom(type)) + throw new InvalidOperationException($"Type {type.FullName} does not implement {typeof(IMigration).FullName}."); + return true; + } + var temp = new HashSet(); + var postMigrationTypes = PreparePostMigrations(context.PostMigrations) + .Where(x => !temp.Contains(x) && EnsureMigrationType(x)) + .Select(x => { temp.Add(x); return x; }); + + // run post-migrations + foreach (var postMigrationType in postMigrationTypes) + { + logger.Info($"PostMigration: {postMigrationType.FullName}."); + var postMigration = migrationBuilder.Build(postMigrationType, context); + postMigration.Migrate(); + } + logger.Info("Done (pending scope completion)."); // safety check diff --git a/src/Umbraco.Core/Migrations/PostMigrationCollection.cs b/src/Umbraco.Core/Migrations/PostMigrationCollection.cs deleted file mode 100644 index 488bdfd72d..0000000000 --- a/src/Umbraco.Core/Migrations/PostMigrationCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Migrations -{ - public class PostMigrationCollection : BuilderCollectionBase - { - public PostMigrationCollection(IEnumerable items) - : base(items) - { } - } -} diff --git a/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs b/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs deleted file mode 100644 index b23d4f1c9c..0000000000 --- a/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Migrations -{ - public class PostMigrationCollectionBuilder : LazyCollectionBuilderBase - { - protected override PostMigrationCollectionBuilder This => this; - - protected override Lifetime CollectionLifetime => Lifetime.Transient; - } -} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs b/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..1b0549827e --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Rebuilds the published snapshot. + /// + /// + /// This interface exists because the entire published snapshot lives in Umbraco.Web + /// but we may want to trigger rebuilds from Umbraco.Core. These two assemblies should + /// be refactored, really. + /// + public interface IPublishedSnapshotRebuilder + { + /// + /// Rebuilds. + /// + void Rebuild(); + } +} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs b/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..acc943b297 --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Implements in Umbraco.Core (doing nothing). + /// + public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder + { + /// + public void Rebuild() + { } + } +} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs b/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs new file mode 100644 index 0000000000..4905699fd4 --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Rebuilds the published snapshot. + /// + public class RebuildPublishedSnapshot : IMigration + { + private readonly IPublishedSnapshotRebuilder _rebuilder; + + /// + /// Initializes a new instance of the class. + /// + public RebuildPublishedSnapshot(IPublishedSnapshotRebuilder rebuilder) + { + _rebuilder = rebuilder; + } + + /// + public void Migrate() + { + _rebuilder.Rebuild(); + } + } +} diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 0cd6ac8b16..4fa687fa5d 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -56,7 +56,7 @@ namespace Umbraco.Core.Migrations.Upgrade } } - // define the plan + // define the plan protected void DefinePlan() { // MODIFYING THE PLAN @@ -128,7 +128,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); To("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}"); - + Merge() .To("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}") .With() diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs deleted file mode 100644 index ac87b8c94d..0000000000 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Configuration; -using Semver; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Migrations.Upgrade -{ - /// - /// Represents the Umbraco upgrader. - /// - public class UmbracoUpgrader : Upgrader - { - private PostMigrationCollection _postMigrations; - - /// - /// Initializes a new instance of the class. - /// - public UmbracoUpgrader() - : base(new UmbracoPlan()) - { } - - /// - /// Executes. - /// - public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) - { - _postMigrations = postMigrations; - Execute(scopeProvider, migrationBuilder, keyValueService, logger); - } - - /// - public override void AfterMigrations(IScope scope, ILogger logger) - { - // assume we have something in web.config that makes some sense = the origin version - if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var originVersion)) - throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting."); - - // target version is the code version - var targetVersion = UmbracoVersion.SemanticVersion; - - foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, logger); - } - } -} diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs index 2d1a4c1650..b4faddb5d0 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PackageActions; using Umbraco.Core.Persistence; @@ -113,13 +114,13 @@ namespace Umbraco.Core.Runtime composition.WithCollectionBuilder() .Append(); - composition.WithCollectionBuilder() - .Add(() => composition.TypeLoader.GetTypes()); - composition.RegisterUnique(factory => new MigrationBuilder(factory)); // by default, register a noop factory composition.RegisterUnique(); + + // by default, register a noop rebuilder + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index 9ddbb09748..55255b418d 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -242,7 +242,7 @@ namespace Umbraco.Core protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { - var upgrader = new UmbracoUpgrader(); + var upgrader = new Upgrader(new UmbracoPlan()); var stateValueKey = upgrader.StateValueKey; // no scope, no service - just directly accessing the database diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f6e8a9c9de..08a2c552cb 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -351,6 +351,9 @@ + + + @@ -666,15 +669,11 @@ - - - - diff --git a/src/Umbraco.Tests/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index 8e84f88265..6b2d21e4a5 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -16,32 +16,6 @@ namespace Umbraco.Tests.Migrations [TestFixture] public class MigrationTests { - public class TestUpgraderWithPostMigrations : Upgrader - { - private PostMigrationCollection _postMigrations; - - public TestUpgraderWithPostMigrations(MigrationPlan plan) - : base(plan) - { } - - public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) - { - _postMigrations = postMigrations; - Execute(scopeProvider, migrationBuilder, keyValueService, logger); - } - - public override void AfterMigrations(IScope scope, ILogger logger) - { - // run post-migrations - var originVersion = new SemVersion(0); - var targetVersion = new SemVersion(0); - - // run post-migrations - foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, logger); - } - } - public class TestScopeProvider : IScopeProvider { private readonly IScope _scope; diff --git a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs index 95f1f8afac..11241d86d9 100644 --- a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs @@ -2,10 +2,9 @@ using Moq; using NPoco; using NUnit.Framework; -using Semver; -using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations; +using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; @@ -18,15 +17,10 @@ namespace Umbraco.Tests.Migrations public class PostMigrationTests { [Test] - public void Executes_For_Any_Product_Name_When_Not_Specified() + public void ExecutesPlanPostMigration() { var logger = Mock.Of(); - var changed1 = new Args { CountExecuted = 0 }; - var post1 = new TestPostMigration(changed1); - - var posts = new PostMigrationCollection(new [] { post1 }); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -34,8 +28,10 @@ namespace Umbraco.Tests.Migrations { switch (t.Name) { - case "NoopMigration": + case nameof(NoopMigration): return new NoopMigration(); + case nameof(TestPostMigration): + return new TestPostMigration(); default: throw new NotSupportedException(); } @@ -50,26 +46,23 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test").From(string.Empty).To("done")); - u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + var plan = new MigrationPlan("Test") + .From(string.Empty).To("done"); - Assert.AreEqual(1, changed1.CountExecuted); + plan.AddPostMigration(); + TestPostMigration.MigrateCount = 0; + + var upgrader = new Upgrader(plan); + upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + + Assert.AreEqual(1, TestPostMigration.MigrateCount); } [Test] - public void Executes_Only_For_Specified_Product_Name() + public void MigrationCanAddPostMigration() { var logger = Mock.Of(); - var changed1 = new Args { CountExecuted = 0}; - var post1 = new TestPostMigration("Test1", changed1); - - var changed2 = new Args { CountExecuted = 0 }; - var post2 = new TestPostMigration("Test2", changed2); - - var posts = new PostMigrationCollection(new [] { post1, post2 }); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -77,8 +70,12 @@ namespace Umbraco.Tests.Migrations { switch (t.Name) { - case "NoopMigration": + case nameof(NoopMigration): return new NoopMigration(); + case nameof(TestMigration): + return new TestMigration(c); + case nameof(TestPostMigration): + return new TestPostMigration(); default: throw new NotSupportedException(); } @@ -93,52 +90,44 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test1").From(string.Empty).To("done")); - u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + var plan = new MigrationPlan("Test") + .From(string.Empty).To("done"); - Assert.AreEqual(1, changed1.CountExecuted); - Assert.AreEqual(0, changed2.CountExecuted); + TestMigration.MigrateCount = 0; + TestPostMigration.MigrateCount = 0; - var u2 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test2").From(string.Empty).To("done")); - u2.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + new MigrationContext(database, logger); - Assert.AreEqual(1, changed1.CountExecuted); - Assert.AreEqual(1, changed2.CountExecuted); + var upgrader = new Upgrader(plan); + upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + + Assert.AreEqual(1, TestMigration.MigrateCount); + Assert.AreEqual(1, TestPostMigration.MigrateCount); } - public class Args + public class TestMigration : MigrationBase { - public int CountExecuted { get; set; } + public TestMigration(IMigrationContext context) + : base(context) + { } + + public static int MigrateCount { get; set; } + + public override void Migrate() + { + MigrateCount++; + + Context.PostMigrations.Add(typeof(TestPostMigration)); + } } - public class TestPostMigration : IPostMigration + public class TestPostMigration : IMigration { - private readonly string _prodName; - private readonly Args _changed; + public static int MigrateCount { get; set; } - // need that one else it breaks IoC - public TestPostMigration() + public void Migrate() { - _changed = new Args(); - } - - public TestPostMigration(Args changed) - { - _changed = changed; - } - - public TestPostMigration(string prodName, Args changed) - { - _prodName = prodName; - _changed = changed; - } - - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (_prodName.IsNullOrWhiteSpace() == false && name != _prodName) return; - _changed.CountExecuted++; + MigrateCount++; } } } diff --git a/src/Umbraco.Web/Editors/NuCacheStatusController.cs b/src/Umbraco.Web/Editors/NuCacheStatusController.cs index fb4b54c2b2..86dbdd4e01 100644 --- a/src/Umbraco.Web/Editors/NuCacheStatusController.cs +++ b/src/Umbraco.Web/Editors/NuCacheStatusController.cs @@ -14,8 +14,7 @@ namespace Umbraco.Web.Editors public NuCacheStatusController(IPublishedSnapshotService publishedSnapshotService) { - if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - _publishedSnapshotService = publishedSnapshotService; + _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); } private PublishedSnapshotService PublishedSnapshotService diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index e8046bd196..4e8068c4c5 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -5,7 +5,10 @@ using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.Upgrade; using Umbraco.Web.Install.Models; +using Umbraco.Web.Migrations; +using Umbraco.Web.Migrations.PostMigrations; namespace Umbraco.Web.Install.InstallSteps { @@ -34,7 +37,10 @@ namespace Umbraco.Web.Install.InstallSteps { _logger.Info("Running 'Upgrade' service"); - var result = _databaseBuilder.UpgradeSchemaAndData(); + var plan = new UmbracoPlan(); + plan.AddPostMigration(); // needed when running installer (back-office) + + var result = _databaseBuilder.UpgradeSchemaAndData(plan); if (result.Success == false) { diff --git a/src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs b/src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs similarity index 50% rename from src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs rename to src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs index 75ba97097b..2267f775be 100644 --- a/src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs +++ b/src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs @@ -1,21 +1,16 @@ using System.Web; -using Semver; -using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations; -using Umbraco.Core.Scoping; using Umbraco.Web.WebApi.Filters; -namespace Umbraco.Web.Migrations +namespace Umbraco.Web.Migrations.PostMigrations { /// - /// After upgrade we clear out the csrf tokens + /// Clears Csrf tokens. /// - public class ClearCsrfCookiesAfterUpgrade : IPostMigration + public class ClearCsrfCookies : IMigration { - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) + public void Migrate() { - if (name != Constants.System.UmbracoUpgradePlanName) return; if (HttpContext.Current == null) return; var http = new HttpContextWrapper(HttpContext.Current); diff --git a/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs b/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..f89c9b1c52 --- /dev/null +++ b/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs @@ -0,0 +1,28 @@ +using Umbraco.Core.Migrations.PostMigrations; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Web.Migrations.PostMigrations +{ + /// + /// Implements in Umbraco.Web (rebuilding). + /// + public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder + { + private readonly IPublishedSnapshotService _publishedSnapshotService; + + /// + /// Initializes a new instance of the class. + /// + /// + public PublishedSnapshotRebuilder(IPublishedSnapshotService publishedSnapshotService) + { + _publishedSnapshotService = publishedSnapshotService; + } + + /// + public void Rebuild() + { + _publishedSnapshotService.Rebuild(); + } + } +} diff --git a/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs index ccdac5664d..6d73be59e3 100644 --- a/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs @@ -48,6 +48,21 @@ namespace Umbraco.Web.PublishedCache #endregion + #region Rebuild + + /// + /// Rebuilds caches. + /// + /// + /// Forces the snapshot service to rebuild its internal caches. For instance, some caches + /// may rely on a database table to store pre-serialized version of documents. + /// This does *not* reload the caches. Caches need to be reloaded, for instance via + /// RefreshAllPublishedSnapshot method. + /// + void Rebuild(); + + #endregion + #region Preview /* Later on we can imagine that EnterPreview would handle a "level" that would be either diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index cc1216eb68..aebb58fa8d 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1277,6 +1277,20 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Rebuild Database PreCache + public override void Rebuild() + { + using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) + { + scope.ReadLock(Constants.Locks.ContentTree); + scope.ReadLock(Constants.Locks.MediaTree); + scope.ReadLock(Constants.Locks.MemberTree); + RebuildContentDbCacheLocked(scope, 5000, null); + RebuildMediaDbCacheLocked(scope, 5000, null); + RebuildMemberDbCacheLocked(scope, 5000, null); + scope.Complete(); + } + } + public void RebuildContentDbCache(int groupSize = 5000, IEnumerable contentTypeIds = null) { using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) diff --git a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs index 74e08e92e8..20d3e6d8e3 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs @@ -33,6 +33,9 @@ namespace Umbraco.Web.PublishedCache public abstract void Notify(DataTypeCacheRefresher.JsonPayload[] payloads); public abstract void Notify(DomainCacheRefresher.JsonPayload[] payloads); + public virtual void Rebuild() + { } + public virtual void Dispose() { } } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 52373184b4..6e82177c89 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -9,6 +9,8 @@ using Umbraco.Core.Composing; using Umbraco.Core.Dashboards; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Migrations.PostMigrations; +using Umbraco.Web.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -249,6 +251,9 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append(); + + // replace with web implementation + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 26624ee4a2..f8570d6dcc 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -196,6 +196,7 @@ + @@ -885,7 +886,7 @@ - +