From b20ce5a92ea8adcc2b134679ca0c7aae8225495f Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 09:50:05 +1100 Subject: [PATCH 01/16] A bunch of cleanup for DI namespaces, ext methods and dist cache classes --- .../Cache/DistributedCacheBinderComponent.cs | 22 -- .../Composing/CollectionBuilderBase.cs | 3 +- .../Composing/CompositionExtensions.cs | 3 +- .../Composing/TypeCollectionBuilderBase.cs | 1 + .../ServiceCollectionExtensions.cs | 9 +- .../ServiceProviderExtensions.cs | 8 +- .../UmbracoBuilder.Collections.cs} | 20 +- .../DependencyInjection/UmbracoBuilder.cs | 29 +- src/Umbraco.Core/IO/FileSystems.cs | 1 + .../Sync/IBatchedDatabaseServerMessenger.cs | 6 +- .../Sync/IDatabaseServerMessenger.cs | 7 - src/Umbraco.Core/Sync/IServerMessenger.cs | 10 +- src/Umbraco.Core/Sync/IServerRegistrar.cs | 4 +- .../ExamineLuceneComposer.cs | 1 - .../BatchedDatabaseServerMessenger.cs | 28 +- ...abaseServerMessengerNotificationHandler.cs | 93 +++++ .../Cache/DistributedCacheBinderComposer.cs | 20 -- ...aseServerRegistrarAndMessengerComponent.cs | 121 ------- .../Compose/NotificationsComposer.cs | 3 +- .../CompositionExtensions/FileSystems.cs | 1 + .../CompositionExtensions/Installer.cs | 1 - .../CompositionExtensions.cs | 335 ------------------ .../UmbracoBuilder.Collections.cs | 96 +++++ .../UmbracoBuilder.CoreServices.cs} | 37 +- .../UmbracoBuilder.DistributedCache.cs | 138 ++++++++ .../UmbracoBuilder.Uniques.cs | 157 ++++++++ .../InstructionProcessTask.cs | 4 +- .../Logging/Serilog/SerilogComposer.cs | 1 - .../Logging/Viewer/LogViewerComposer.cs | 1 + .../Migrations/MigrationBuilder.cs | 1 + .../NoopPublishedSnapshotRebuilder.cs | 12 - .../Scoping/IScopeProvider.cs | 4 +- .../Search/ExamineComposer.cs | 3 +- .../Sync/DatabaseServerMessenger.cs | 157 ++++---- .../Sync/ServerMessengerBase.cs | 4 +- .../WebAssets/WebAssetsComposer.cs | 1 - .../Compose/ModelsBuilderComposer.cs | 1 - .../UmbracoBuilderExtensions.cs | 1 - src/Umbraco.Tests.Integration/RuntimeTests.cs | 47 +-- .../Testing/IntegrationTestComposer.cs | 10 +- .../Scoping/ScopedRepositoryTests.cs | 2 + .../Services/ContentEventsTests.cs | 2 + .../TestHelpers/BaseUsingSqlSyntax.cs | 1 - .../TestHelpers/TestHelper.cs | 1 + .../DistributedCache/DistributedCacheTests.cs | 14 +- .../InstructionProcessTaskTests.cs | 4 +- .../Cache/DistributedCacheBinderTests.cs | 1 - .../PublishedContentLanguageVariantTests.cs | 1 + .../PublishedContentSnapshotTestBase.cs | 2 +- .../PublishedContent/PublishedContentTests.cs | 1 + .../PublishedContent/PublishedMediaTests.cs | 1 + .../Routing/RenderRouteHandlerTests.cs | 1 + ...oviderWithHideTopLevelNodeFromPathTests.cs | 2 +- .../Routing/UrlRoutingTestBase.cs | 2 +- .../Routing/UrlsProviderWithDomainsTests.cs | 2 +- .../Routing/UrlsWithNestedDomains.cs | 2 +- .../Scoping/ScopeEventDispatcherTests.cs | 1 - .../Scoping/ScopedNuCacheTests.cs | 1 + src/Umbraco.Tests/Scoping/ScopedXmlTests.cs | 3 + src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 2 +- src/Umbraco.Tests/TestHelpers/TestHelper.cs | 1 + .../TestHelpers/TestWithDatabaseBase.cs | 1 + src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 + .../UmbracoExamine/ExamineBaseTest.cs | 2 +- .../AuthenticationControllerTests.cs | 2 +- .../Runtime/BackOfficeComposer.cs | 1 - .../UmbracoBuilderExtensions.cs | 7 + .../Extensions/LinkGeneratorExtensions.cs | 3 +- .../UmbracoCoreServiceCollectionExtensions.cs | 2 +- .../Profiler/WebProfilerComposer.cs | 1 - .../Runtime/AspNetCoreBootFailedComposer.cs | 1 - .../RuntimeMinification/SmidgeComposer.cs | 3 +- .../Runtime/WebsiteComposer.cs | 1 - src/Umbraco.Web/UmbracoBuilderExtensions.cs | 1 - 74 files changed, 737 insertions(+), 737 deletions(-) delete mode 100644 src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs rename src/Umbraco.Core/{ => DependencyInjection}/ServiceCollectionExtensions.cs (92%) rename src/Umbraco.Core/{ => DependencyInjection}/ServiceProviderExtensions.cs (96%) rename src/Umbraco.Core/{CompositionExtensions.cs => DependencyInjection/UmbracoBuilder.Collections.cs} (93%) delete mode 100644 src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs create mode 100644 src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs delete mode 100644 src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs delete mode 100644 src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs delete mode 100644 src/Umbraco.Infrastructure/CompositionExtensions.cs create mode 100644 src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs rename src/Umbraco.Infrastructure/{Runtime/CoreInitialServices.cs => DependencyInjection/UmbracoBuilder.CoreServices.cs} (95%) create mode 100644 src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs create mode 100644 src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs delete mode 100644 src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs diff --git a/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs b/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs deleted file mode 100644 index 31e876892e..0000000000 --- a/src/Umbraco.Core/Cache/DistributedCacheBinderComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Cache -{ - public class DistributedCacheBinderComponent : IComponent - { - private readonly IDistributedCacheBinder _binder; - - public DistributedCacheBinderComponent(IDistributedCacheBinder distributedCacheBinder) - { - _binder = distributedCacheBinder; - } - - public void Initialize() - { - _binder.BindEvents(); - } - - public void Terminate() - { } - } -} diff --git a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs index 1c4de6cd8e..14089ba924 100644 --- a/src/Umbraco.Core/Composing/CollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/CollectionBuilderBase.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Composing { diff --git a/src/Umbraco.Core/Composing/CompositionExtensions.cs b/src/Umbraco.Core/Composing/CompositionExtensions.cs index e4e02443eb..d7b143df38 100644 --- a/src/Umbraco.Core/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Core/Composing/CompositionExtensions.cs @@ -1,5 +1,4 @@ -using System; -using Umbraco.Core; +using System; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Web.PublishedCache; diff --git a/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs index edbf554a2c..9229a95cc3 100644 --- a/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/TypeCollectionBuilderBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Composing { diff --git a/src/Umbraco.Core/ServiceCollectionExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs similarity index 92% rename from src/Umbraco.Core/ServiceCollectionExtensions.cs rename to src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs index d1c89ea17e..51ff6b705f 100644 --- a/src/Umbraco.Core/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,9 +1,10 @@ -using System; +using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Umbraco.Core; using Umbraco.Core.Composing; -namespace Umbraco.Core +namespace Umbraco.Core.DependencyInjection { public static class ServiceCollectionExtensions { @@ -21,7 +22,7 @@ namespace Umbraco.Core where TImplementing : class, TService1, TService2 { services.AddUnique(); - services.AddUnique(factory => (TImplementing) factory.GetRequiredService()); + services.AddUnique(factory => (TImplementing)factory.GetRequiredService()); } public static void AddUnique(this IServiceCollection services) @@ -48,7 +49,7 @@ namespace Umbraco.Core /// public static void AddUnique(this IServiceCollection services, TService instance) where TService : class - => services.Replace(ServiceDescriptor.Singleton(instance)); + => services.Replace(ServiceDescriptor.Singleton(instance)); public static IServiceCollection AddLazySupport(this IServiceCollection services) { diff --git a/src/Umbraco.Core/ServiceProviderExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs similarity index 96% rename from src/Umbraco.Core/ServiceProviderExtensions.cs rename to src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs index e0d3da2c03..a1cc779500 100644 --- a/src/Umbraco.Core/ServiceProviderExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/ServiceProviderExtensions.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; +using System; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.Composing; -namespace Umbraco.Core +namespace Umbraco.Core.DependencyInjection { /// /// Provides extension methods to the class. diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs similarity index 93% rename from src/Umbraco.Core/CompositionExtensions.cs rename to src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs index 58aac7b811..35d8ba1025 100644 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -1,4 +1,3 @@ -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.HealthCheck; using Umbraco.Core.Manifest; @@ -11,18 +10,17 @@ using Umbraco.Web.Routing; using Umbraco.Web.Sections; using Umbraco.Web.Tour; -namespace Umbraco.Core +namespace Umbraco.Core.DependencyInjection { - public static partial class CompositionExtensions + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions { - - #region Collection Builders - /// /// Gets the actions collection builder. /// /// The builder. - /// public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); @@ -30,7 +28,6 @@ namespace Umbraco.Core /// Gets the content apps collection builder. /// /// The builder. - /// public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); @@ -38,7 +35,6 @@ namespace Umbraco.Core /// Gets the content finders collection builder. /// /// The builder. - /// public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); @@ -46,7 +42,6 @@ namespace Umbraco.Core /// Gets the editor validators collection builder. /// /// The builder. - /// public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); @@ -90,7 +85,6 @@ namespace Umbraco.Core public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); - /// /// Gets the backoffice dashboards collection builder. /// @@ -109,15 +103,11 @@ namespace Umbraco.Core .Add() .Add(); - /// /// Gets the content finders collection builder. /// /// The builder. - /// public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); - - #endregion } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index d56712cdcf..1c05695429 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -14,17 +14,26 @@ namespace Umbraco.Core.DependencyInjection { public class UmbracoBuilder : IUmbracoBuilder { - public IServiceCollection Services { get; } - public IConfiguration Config { get; } - public TypeLoader TypeLoader { get; } - public ILoggerFactory BuilderLoggerFactory { get; } - private readonly Dictionary _builders = new Dictionary(); + public IServiceCollection Services { get; } + + public IConfiguration Config { get; } + + public TypeLoader TypeLoader { get; } + + public ILoggerFactory BuilderLoggerFactory { get; } + + /// + /// Initializes a new instance of the class. + /// public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader) : this(services, config, typeLoader, NullLoggerFactory.Instance) { } + /// + /// Initializes a new instance of the class. + /// public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory) { Services = services; @@ -43,10 +52,12 @@ namespace Umbraco.Core.DependencyInjection public TBuilder WithCollectionBuilder() where TBuilder : ICollectionBuilder, new() { - var typeOfBuilder = typeof(TBuilder); + Type typeOfBuilder = typeof(TBuilder); - if (_builders.TryGetValue(typeOfBuilder, out var o)) + if (_builders.TryGetValue(typeOfBuilder, out ICollectionBuilder o)) + { return (TBuilder)o; + } var builder = new TBuilder(); _builders[typeOfBuilder] = builder; @@ -55,8 +66,10 @@ namespace Umbraco.Core.DependencyInjection public void Build() { - foreach (var builder in _builders.Values) + foreach (ICollectionBuilder builder in _builders.Values) + { builder.RegisterWith(Services); + } _builders.Clear(); } diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index b078172213..62f46edce4 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.IO { diff --git a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs index 560b7fb235..02859ff6f0 100644 --- a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs @@ -3,10 +3,10 @@ namespace Umbraco.Core.Sync /// /// An implementation that works by storing messages in the database. /// - public interface IBatchedDatabaseServerMessenger : IDatabaseServerMessenger + public interface IBatchedDatabaseServerMessenger : IServerMessenger { + // TODO: We only ever use IBatchedDatabaseServerMessenger so just combine these interfaces + void FlushBatch(); - DatabaseServerMessengerCallbacks Callbacks { get; } - void Startup(); } } diff --git a/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs deleted file mode 100644 index a49cfdd023..0000000000 --- a/src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Sync -{ - public interface IDatabaseServerMessenger: IServerMessenger - { - void Sync(); - } -} diff --git a/src/Umbraco.Core/Sync/IServerMessenger.cs b/src/Umbraco.Core/Sync/IServerMessenger.cs index b8300b2d6d..a6c5b5d755 100644 --- a/src/Umbraco.Core/Sync/IServerMessenger.cs +++ b/src/Umbraco.Core/Sync/IServerMessenger.cs @@ -1,15 +1,19 @@ -using System; -using System.Collections.Generic; +using System; using Umbraco.Core.Cache; namespace Umbraco.Core.Sync { /// - /// Broadcasts distributed cache notifications to all servers of a load balanced environment. + /// Transmits distributed cache notifications for all servers of a load balanced environment. /// /// Also ensures that the notification is processed on the local environment. public interface IServerMessenger { + /// + /// Called to synchronize a server with queued notifications + /// + void Sync(); + /// /// Notifies the distributed cache, for a specified . /// diff --git a/src/Umbraco.Core/Sync/IServerRegistrar.cs b/src/Umbraco.Core/Sync/IServerRegistrar.cs index 780f865ad7..7e63b6b170 100644 --- a/src/Umbraco.Core/Sync/IServerRegistrar.cs +++ b/src/Umbraco.Core/Sync/IServerRegistrar.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace Umbraco.Core.Sync { @@ -10,7 +10,7 @@ namespace Umbraco.Core.Sync /// /// Gets the server registrations. /// - IEnumerable Registrations { get; } + IEnumerable Registrations { get; } // TODO: This isn't even used anymore, this whole interface can probably go away /// /// Gets the role of the current server in the application environment. diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs index e2f2460d58..05315b05fe 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs @@ -1,5 +1,4 @@ using System.Runtime.InteropServices; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index 187eced6e4..bafb537db6 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -25,13 +25,11 @@ namespace Umbraco.Web /// public class BatchedDatabaseServerMessenger : DatabaseServerMessenger, IBatchedDatabaseServerMessenger { - private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IRequestCache _requestCache; private readonly IRequestAccessor _requestAccessor; public BatchedDatabaseServerMessenger( IMainDom mainDom, - IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, IProfilingLogger proflog, ILogger logger, @@ -42,34 +40,12 @@ namespace Umbraco.Web IRequestCache requestCache, IRequestAccessor requestAccessor, IOptions globalSettings) - : base(mainDom, scopeProvider, databaseFactory, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings) + : base(mainDom, scopeProvider, proflog, logger, serverRegistrar, true, callbacks, hostingEnvironment, cacheRefreshers, globalSettings) { - _databaseFactory = databaseFactory; _requestCache = requestCache; _requestAccessor = requestAccessor; } - // invoked by DatabaseServerRegistrarAndMessengerComponent - public void Startup() - { - _requestAccessor.EndRequest += UmbracoModule_EndRequest; - - if (_databaseFactory.CanConnect == false) - { - Logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server."); - } - else - { - Boot(); - } - } - - private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e) - { - // will clear the batch - will remain in HttpContext though - that's ok - FlushBatch(); - } - protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { var idsA = ids?.ToArray(); diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs new file mode 100644 index 0000000000..b0921f7698 --- /dev/null +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -0,0 +1,93 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Events; +using Umbraco.Core.Persistence; +using Umbraco.Core.Sync; +using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.Routing; + +namespace Umbraco.Infrastructure.Cache +{ + /// + /// Ensures that distributed cache events are setup and the is initialized + /// + public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler + { + private readonly IBatchedDatabaseServerMessenger _messenger; + private readonly IRequestAccessor _requestAccessor; + private readonly IUmbracoDatabaseFactory _databaseFactory; + private readonly IDistributedCacheBinder _distributedCacheBinder; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + public DatabaseServerMessengerNotificationHandler( + IServerMessenger serverMessenger, + IRequestAccessor requestAccessor, + IUmbracoDatabaseFactory databaseFactory, + IDistributedCacheBinder distributedCacheBinder, + ILogger logger) + { + _requestAccessor = requestAccessor; + _databaseFactory = databaseFactory; + _distributedCacheBinder = distributedCacheBinder; + _logger = logger; + _messenger = serverMessenger as IBatchedDatabaseServerMessenger; + } + + /// + public Task HandleAsync(UmbracoApplicationStarting notification, CancellationToken cancellationToken) + { + // The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services. + // The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL + // being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured). + // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available + // for the hosted services to use when the HTTP request is not available. + _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; + _requestAccessor.EndRequest += UmbracoModule_EndRequest; + + Startup(); + + return Task.CompletedTask; + } + + private void Startup() + { + if (_databaseFactory.CanConnect == false) + { + _logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server."); + } + else + { + _distributedCacheBinder.BindEvents(); + + // Sync on startup, this will run through the messenger's initialization sequence + _messenger?.Sync(); + } + } + + // TODO: I don't really know or think that the Application Url plays a role anymore with the DB dist cache, + // this might be really old stuff + private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) + { + if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) + { + _requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce; + EnsureApplicationUrl(); + } + } + + // By retrieving the application URL within the context of a request (as we are here in responding + // to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for + // future requests that may not be within an HTTP request (e.g. from hosted services). + private void EnsureApplicationUrl() => _requestAccessor.GetApplicationUrl(); + + /// + /// Clear the batch on end request + /// + private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.FlushBatch(); + } +} diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs deleted file mode 100644 index 7279eaf10c..0000000000 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Cache -{ - /// - /// Installs listeners on service events in order to refresh our caches. - /// - [ComposeBefore(typeof(ICoreComposer))] // runs before every other IUmbracoCoreComponent! - public sealed class DistributedCacheBinderComposer : ComponentComposer, ICoreComposer - { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs deleted file mode 100644 index 8d2a2e19cc..0000000000 --- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Services.Changes; -using Umbraco.Core.Sync; -using Umbraco.Web.Cache; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Search; - -namespace Umbraco.Web.Compose -{ - /// - /// Ensures that servers are automatically registered in the database, when using the database server registrar. - /// - /// - /// At the moment servers are automatically registered upon first request and then on every - /// request but not more than once per (configurable) period. This really is "for information & debug" purposes so - /// we can look at the table and see what servers are registered - but the info is not used anywhere. - /// Should we actually want to use this, we would need a better and more deterministic way of figuring - /// out the "server address" ie the address to which server-to-server requests should be sent - because it - /// probably is not the "current request address" - especially in multi-domains configurations. - /// - // during Initialize / Startup, we end up checking Examine, which needs to be initialized beforehand - // TODO: should not be a strong dependency on "examine" but on an "indexing component" - [ComposeAfter(typeof(ExamineComposer))] - - public sealed class DatabaseServerRegistrarAndMessengerComposer : ComponentComposer, ICoreComposer - { - public static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory) - { - return new DatabaseServerMessengerCallbacks - { - //These callbacks will be executed if the server has not been synced - // (i.e. it is a new server or the lastsynced.txt file has been removed) - InitializingCallbacks = new Action[] - { - //rebuild the xml cache file if the server is not synced - () => - { - var publishedSnapshotService = factory.GetRequiredService(); - - // rebuild the published snapshot caches entirely, if the server is not synced - // this is equivalent to DistributedCache RefreshAll... but local only - // (we really should have a way to reuse RefreshAll... locally) - // note: refresh all content & media caches does refresh content types too - publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) }); - publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); - publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); - }, - - //rebuild indexes if the server is not synced - // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific - // indexes then they can adjust this logic themselves. - () => - { - var indexRebuilder = factory.GetRequiredService(); - indexRebuilder.RebuildIndexes(false, 5000); - } - } - }; - } - - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); - builder.SetServerMessenger(); - } - } - - public sealed class DatabaseServerRegistrarAndMessengerComponent : IComponent - { - private readonly IBatchedDatabaseServerMessenger _messenger; - private readonly IRequestAccessor _requestAccessor; - - public DatabaseServerRegistrarAndMessengerComponent( - IServerMessenger serverMessenger, - IRequestAccessor requestAccessor) - { - _requestAccessor = requestAccessor; - _messenger = serverMessenger as IBatchedDatabaseServerMessenger; - } - - public void Initialize() - { - // The scheduled tasks - TouchServerTask and InstructionProcessTask - run as .NET Core hosted services. - // The former (as well as other hosted services that run outside of an HTTP request context) depends on the application URL - // being available (via IRequestAccessor), which can only be retrieved within an HTTP request (unless it's explicitly configured). - // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available - // for the hosted services to use when the HTTP request is not available. - _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; - - // Must come last, as it references some _variables - _messenger?.Startup(); - } - - public void Terminate() - { } - - private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) - { - if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) - { - _requestAccessor.RouteAttempt -= EnsureApplicationUrlOnce; - EnsureApplicationUrl(); - } - } - - private void EnsureApplicationUrl() - { - // By retrieving the application URL within the context of a request (as we are here in responding - // to the IRequestAccessor's RouteAttempt event), we'll get it from the HTTP context and save it for - // future requests that may not be within an HTTP request (e.g. from hosted services). - _requestAccessor.GetApplicationUrl(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs index 0fee815560..79066dedd7 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; namespace Umbraco.Web.Compose diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs index f098cfaf57..4c8caa89b8 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Strings; +using Umbraco.Infrastructure.DependencyInjection; namespace Umbraco.Core.Composing.CompositionExtensions { diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs index 31b3133e4d..dc3b1e2481 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Web.Install; diff --git a/src/Umbraco.Infrastructure/CompositionExtensions.cs b/src/Umbraco.Infrastructure/CompositionExtensions.cs deleted file mode 100644 index 703c35e06b..0000000000 --- a/src/Umbraco.Infrastructure/CompositionExtensions.cs +++ /dev/null @@ -1,335 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Dictionary; -using Umbraco.Core.IO; -using Umbraco.Core.Logging.Viewer; -using Umbraco.Core.Manifest; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PackageActions; -using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Strings; -using Umbraco.Core.Sync; -using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Search; - -namespace Umbraco.Core -{ - /// - /// Provides extension methods to the class. - /// - public static partial class CompositionExtensions - { - #region Collection Builders - - /// - /// Gets the cache refreshers collection builder. - /// - /// The builder. - public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the mappers collection builder. - /// - /// The builder. - public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the package actions collection builder. - /// - /// The builder. - internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data editor collection builder. - /// - /// The builder. - public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data value reference factory collection builder. - /// - /// The builder. - public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the property value converters collection builder. - /// - /// The builder. - public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the url segment providers collection builder. - /// - /// The builder. - public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the validators collection builder. - /// - /// The builder. - internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the manifest filter collection builder. - /// - /// The builder. - public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the backoffice OEmbed Providers collection builder. - /// - /// The builder. - public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the back office searchable tree collection builder - /// - /// - /// - public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - #endregion - - #region Uniques - - /// - /// Sets the culture dictionary factory. - /// - /// The type of the factory. - /// The builder. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder) - where T : class, ICultureDictionaryFactory - { - builder.Services.AddUnique(); - } - - /// - /// Sets the culture dictionary factory. - /// - /// The builder. - /// A function creating a culture dictionary factory. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the culture dictionary factory. - /// - /// The builder. - /// A factory. - public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the published content model factory. - /// - /// The type of the factory. - /// The builder. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder) - where T : class, IPublishedModelFactory - { - builder.Services.AddUnique(); - } - - /// - /// Sets the published content model factory. - /// - /// The builder. - /// A function creating a published content model factory. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the published content model factory. - /// - /// The builder. - /// A published content model factory. - public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server registrar. - /// - /// The type of the server registrar. - /// The builder. - public static void SetServerRegistrar(this IUmbracoBuilder builder) - where T : class, IServerRegistrar - { - builder.Services.AddUnique(); - } - - /// - /// Sets the server registrar. - /// - /// The builder. - /// A function creating a server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server registrar. - /// - /// The builder. - /// A server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar) - { - builder.Services.AddUnique(registrar); - } - - /// - /// Sets the server messenger. - /// - /// The type of the server registrar. - /// The builder. - public static void SetServerMessenger(this IUmbracoBuilder builder) - where T : class, IServerMessenger - { - builder.Services.AddUnique(); - } - - /// - /// Sets the server messenger. - /// - /// The builder. - /// A function creating a server messenger. - public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the server messenger. - /// - /// The builder. - /// A server messenger. - public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar) - { - builder.Services.AddUnique(registrar); - } - - /// - /// Sets the database server messenger options. - /// - /// The builder. - /// A function creating the options. - /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. - public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the database server messenger options. - /// - /// The builder. - /// Options. - /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. - public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) - { - builder.Services.AddUnique(options); - } - - /// - /// Sets the short string helper. - /// - /// The type of the short string helper. - /// The builder. - public static void SetShortStringHelper(this IUmbracoBuilder builder) - where T : class, IShortStringHelper - { - builder.Services.AddUnique(); - } - - /// - /// Sets the short string helper. - /// - /// The builder. - /// A function creating a short string helper. - public static void SetShortStringHelper(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the short string helper. - /// - /// A builder. - /// A short string helper. - public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper) - { - builder.Services.AddUnique(helper); - } - - /// - /// Sets the underlying media filesystem. - /// - /// A builder. - /// A filesystem factory. - /// - /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper - /// - public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) - => builder.Services.AddUnique(factory => - { - var fileSystems = factory.GetRequiredService(); - return fileSystems.GetFileSystem(filesystemFactory(factory)); - }); - - /// - /// Sets the log viewer. - /// - /// The type of the log viewer. - /// The builder. - public static void SetLogViewer(this IUmbracoBuilder builder) - where T : class, ILogViewer - { - builder.Services.AddUnique(); - } - - /// - /// Sets the log viewer. - /// - /// The builder. - /// A function creating a log viewer. - public static void SetLogViewer(this IUmbracoBuilder builder, Func factory) - { - builder.Services.AddUnique(factory); - } - - /// - /// Sets the log viewer. - /// - /// A builder. - /// A log viewer. - public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer) - { - builder.Services.AddUnique(viewer); - } - - #endregion - } -} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs new file mode 100644 index 0000000000..28bed7b363 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs @@ -0,0 +1,96 @@ +using Umbraco.Core.Cache; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Manifest; +using Umbraco.Core.PackageActions; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using Umbraco.Web.Media.EmbedProviders; +using Umbraco.Web.Search; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Gets the cache refreshers collection builder. + /// + /// The builder. + public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the mappers collection builder. + /// + /// The builder. + public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the package actions collection builder. + /// + /// The builder. + internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data editor collection builder. + /// + /// The builder. + public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data value reference factory collection builder. + /// + /// The builder. + public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the property value converters collection builder. + /// + /// The builder. + public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the url segment providers collection builder. + /// + /// The builder. + public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the validators collection builder. + /// + /// The builder. + internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the manifest filter collection builder. + /// + /// The builder. + public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice OEmbed Providers collection builder. + /// + /// The builder. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the back office searchable tree collection builder + /// + /// + /// + public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + } +} diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs similarity index 95% rename from src/Umbraco.Infrastructure/Runtime/CoreInitialServices.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index 32f5e6bf36..e150f0cdba 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -1,7 +1,6 @@ using System; using Examine; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; @@ -13,9 +12,7 @@ using Umbraco.Core.Dashboards; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; -using Umbraco.Core.Hosting; using Umbraco.Core.Install; -using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Media; using Umbraco.Core.Migrations; @@ -23,7 +20,6 @@ using Umbraco.Core.Migrations.Install; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Packaging; -using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -38,6 +34,7 @@ using Umbraco.Core.Templates; using Umbraco.Examine; using Umbraco.Infrastructure.Examine; using Umbraco.Infrastructure.Media; +using Umbraco.Infrastructure.Runtime; using Umbraco.Web; using Umbraco.Web.Actions; using Umbraco.Web.Cache; @@ -62,10 +59,30 @@ using Umbraco.Web.Templates; using Umbraco.Web.Trees; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; -namespace Umbraco.Infrastructure.Runtime +namespace Umbraco.Infrastructure.DependencyInjection { - public static class CoreInitialServices + public static partial class UmbracoBuilderExtensions { + + /* + * TODO: Many of these things are not "Core" services and are probably not required to run + * + * This should be split up: + * - Distributed Cache + * - BackOffice + * - Manifest + * - Property Editors + * - Packages + * - Dashboards + * - OEmbed + * - Sections + * - Content Apps + * - Health Checks + * - ETC... + * - Installation + * - Front End + */ + public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder) { builder.AddNotificationHandler(); @@ -130,7 +147,7 @@ namespace Umbraco.Infrastructure.Runtime builder.DataValueReferenceFactories(); // register a server registrar, by default it's the db registrar - builder.Services.AddUnique(f => + builder.Services.AddUnique(f => { var globalSettings = f.GetRequiredService>().Value; @@ -138,7 +155,7 @@ namespace Umbraco.Infrastructure.Runtime // even on 1 single server we can have 2 concurrent app domains var singleServer = globalSettings.DisableElectionForSingleServer; return singleServer - ? (IServerRegistrar) new SingleServerRegistrar(f.GetRequiredService()) + ? (IServerRegistrar)new SingleServerRegistrar(f.GetRequiredService()) : new DatabaseServerRegistrar( new Lazy(f.GetRequiredService)); }); @@ -183,7 +200,6 @@ namespace Umbraco.Infrastructure.Runtime // by default, register a noop factory builder.Services.AddUnique(); - // by default builder.Services.AddUnique(); builder.SetCultureDictionaryFactory(); @@ -253,10 +269,8 @@ namespace Umbraco.Infrastructure.Runtime builder.EditorValidators() .Add(() => builder.TypeLoader.GetTypes()); - builder.TourFilters(); - // replace with web implementation builder.Services.AddUnique(); // register OEmbed providers - no type scanning - all explicit opt-in of adding types @@ -338,7 +352,6 @@ namespace Umbraco.Infrastructure.Runtime // register distributed cache builder.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); - builder.Services.AddScoped(); builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs new file mode 100644 index 0000000000..4970df2b87 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -0,0 +1,138 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Events; +using Umbraco.Core.Services.Changes; +using Umbraco.Core.Sync; +using Umbraco.Infrastructure.Cache; +using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.Search; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds distributed cache support + /// + public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder) + { + // NOTE: the `DistributedCache` is registered in AddCoreInitialServices since it's a core service + + builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); + builder.SetServerMessenger(); + builder.AddNotificationHandler(); + + builder.CacheRefreshers() + .Add(() => builder.TypeLoader.GetCacheRefreshers()); + + builder.Services.AddUnique(); + return builder; + } + + /// + /// Sets the server registrar. + /// + /// The type of the server registrar. + /// The builder. + public static void SetServerRegistrar(this IUmbracoBuilder builder) + where T : class, IServerRegistrar + => builder.Services.AddUnique(); + + /// + /// Sets the server registrar. + /// + /// The builder. + /// A function creating a server registrar. + public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the server registrar. + /// + /// The builder. + /// A server registrar. + public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar) + => builder.Services.AddUnique(registrar); + + /// + /// Sets the database server messenger options. + /// + /// The builder. + /// A function creating the options. + /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. + public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the database server messenger options. + /// + /// The builder. + /// Options. + /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. + public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) + => builder.Services.AddUnique(options); + + /// + /// Sets the server messenger. + /// + /// The type of the server registrar. + /// The builder. + public static void SetServerMessenger(this IUmbracoBuilder builder) + where T : class, IServerMessenger + => builder.Services.AddUnique(); + + /// + /// Sets the server messenger. + /// + /// The builder. + /// A function creating a server messenger. + public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) + => builder.Services.AddUnique(factory); + + /// + /// Sets the server messenger. + /// + /// The builder. + /// A server messenger. + public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar) + => builder.Services.AddUnique(registrar); + + private static DatabaseServerMessengerCallbacks GetCallbacks(IServiceProvider factory) => new DatabaseServerMessengerCallbacks + { + // These callbacks will be executed if the server has not been synced + // (i.e. it is a new server or the lastsynced.txt file has been removed) + InitializingCallbacks = new Action[] + { + // rebuild the xml cache file if the server is not synced + () => + { + IPublishedSnapshotService publishedSnapshotService = factory.GetRequiredService(); + + // rebuild the published snapshot caches entirely, if the server is not synced + // this is equivalent to DistributedCache RefreshAll... but local only + // (we really should have a way to reuse RefreshAll... locally) + // note: refresh all content & media caches does refresh content types too + publishedSnapshotService.Notify(new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) }); + publishedSnapshotService.Notify(new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _, out _); + publishedSnapshotService.Notify(new[] { new MediaCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }, out _); + }, + + // rebuild indexes if the server is not synced + // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific + // indexes then they can adjust this logic themselves. + () => + { + var indexRebuilder = factory.GetRequiredService(); + indexRebuilder.RebuildIndexes(false, 5000); + } + } + }; + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs new file mode 100644 index 0000000000..f26b4442f8 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs @@ -0,0 +1,157 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Dictionary; +using Umbraco.Core.IO; +using Umbraco.Core.Logging.Viewer; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Strings; +using Umbraco.Core.Sync; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Sets the culture dictionary factory. + /// + /// The type of the factory. + /// The builder. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder) + where T : class, ICultureDictionaryFactory + { + builder.Services.AddUnique(); + } + + /// + /// Sets the culture dictionary factory. + /// + /// The builder. + /// A function creating a culture dictionary factory. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the culture dictionary factory. + /// + /// The builder. + /// A factory. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the published content model factory. + /// + /// The type of the factory. + /// The builder. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder) + where T : class, IPublishedModelFactory + { + builder.Services.AddUnique(); + } + + /// + /// Sets the published content model factory. + /// + /// The builder. + /// A function creating a published content model factory. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the published content model factory. + /// + /// The builder. + /// A published content model factory. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the short string helper. + /// + /// The type of the short string helper. + /// The builder. + public static void SetShortStringHelper(this IUmbracoBuilder builder) + where T : class, IShortStringHelper + { + builder.Services.AddUnique(); + } + + /// + /// Sets the short string helper. + /// + /// The builder. + /// A function creating a short string helper. + public static void SetShortStringHelper(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the short string helper. + /// + /// A builder. + /// A short string helper. + public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper) + { + builder.Services.AddUnique(helper); + } + + /// + /// Sets the underlying media filesystem. + /// + /// A builder. + /// A filesystem factory. + /// + /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper + /// + public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) + => builder.Services.AddUnique(factory => + { + var fileSystems = factory.GetRequiredService(); + return fileSystems.GetFileSystem(filesystemFactory(factory)); + }); + + /// + /// Sets the log viewer. + /// + /// The type of the log viewer. + /// The builder. + public static void SetLogViewer(this IUmbracoBuilder builder) + where T : class, ILogViewer + { + builder.Services.AddUnique(); + } + + /// + /// Sets the log viewer. + /// + /// The builder. + /// A function creating a log viewer. + public static void SetLogViewer(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the log viewer. + /// + /// A builder. + /// A log viewer. + public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer) + { + builder.Services.AddUnique(viewer); + } + } +} diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs index 3c291f187b..f3d970d2b0 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs @@ -17,7 +17,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration public class InstructionProcessTask : RecurringHostedServiceBase { private readonly IRuntimeState _runtimeState; - private readonly IDatabaseServerMessenger _messenger; + private readonly IServerMessenger _messenger; private readonly ILogger _logger; /// @@ -31,7 +31,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration : base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1)) { _runtimeState = runtimeState; - _messenger = messenger as IDatabaseServerMessenger ?? throw new ArgumentNullException(nameof(messenger)); + _messenger = messenger as IServerMessenger ?? throw new ArgumentNullException(nameof(messenger)); _logger = logger; } diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs index fc26f922eb..4d8046ee8c 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Logging.Serilog.Enrichers; diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs index aa57383541..4c419a1648 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using Serilog; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; +using Umbraco.Infrastructure.DependencyInjection; namespace Umbraco.Core.Logging.Viewer { diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs b/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs index 9fc5b1b277..22961dea5a 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationBuilder.cs @@ -1,5 +1,6 @@ using System; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Core.Migrations { diff --git a/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs b/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs deleted file mode 100644 index cf53f161a4..0000000000 --- a/src/Umbraco.Infrastructure/Migrations/PostMigrations/NoopPublishedSnapshotRebuilder.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Umbraco.Core.Migrations.PostMigrations -{ - /// - /// Implements in Umbraco.Core (doing nothing). - /// - public class NoopPublishedSnapshotRebuilder : IPublishedSnapshotRebuilder - { - /// - public void Rebuild() - { } - } -} diff --git a/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs index dce6658f16..712b90affa 100644 --- a/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/IScopeProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Data; using Umbraco.Core.Events; using Umbraco.Core.Persistence; @@ -13,7 +13,7 @@ namespace Umbraco.Core.Scoping /// Provides scopes. /// public interface IScopeProvider - { + { /// /// Creates an ambient scope. /// diff --git a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs index 683ed48ecd..c961aa6e72 100644 --- a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs +++ b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Models; diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 856772148f..11e1596529 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -23,15 +23,20 @@ namespace Umbraco.Core.Sync /// /// An that works by storing messages in the database. /// - // - // this messenger writes ALL instructions to the database, - // but only processes instructions coming from remote servers, - // thus ensuring that instructions run only once - // - public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger + public abstract class DatabaseServerMessenger : ServerMessengerBase { + // TODO: This class is never used directly, only BatchedDatabaseServerMessenger is used so + // this could/should be combined with that or made abstract and/or just cleaned up. + + // TODO: This class needs to be split into a service/repo for DB access + + /* + * this messenger writes ALL instructions to the database, + * but only processes instructions coming from remote servers, + * thus ensuring that instructions run only once + */ + private readonly IMainDom _mainDom; - private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; private readonly ManualResetEvent _syncIdle; private readonly object _locko = new object(); private readonly IProfilingLogger _profilingLogger; @@ -43,22 +48,28 @@ namespace Umbraco.Core.Sync private int _lastId = -1; private DateTime _lastSync; private DateTime _lastPruned; - private bool _initialized; + private readonly Lazy _initialized; private bool _syncing; private bool _released; - public DatabaseServerMessengerCallbacks Callbacks { get; } - - public GlobalSettings GlobalSettings { get; } - + /// + /// Initializes a new instance of the class. + /// public DatabaseServerMessenger( - IMainDom mainDom, IScopeProvider scopeProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, IProfilingLogger proflog, ILogger logger, IServerRegistrar serverRegistrar, - bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IOptions globalSettings) + IMainDom mainDom, + IScopeProvider scopeProvider, + IProfilingLogger proflog, + ILogger logger, + IServerRegistrar serverRegistrar, + bool distributedEnabled, + DatabaseServerMessengerCallbacks callbacks, + IHostingEnvironment hostingEnvironment, + CacheRefresherCollection cacheRefreshers, + IOptions globalSettings) : base(distributedEnabled) { ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); _mainDom = mainDom; - _umbracoDatabaseFactory = umbracoDatabaseFactory; _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); _serverRegistrar = serverRegistrar; _hostingEnvironment = hostingEnvironment; @@ -76,24 +87,28 @@ namespace Umbraco.Core.Sync + " [P" + Process.GetCurrentProcess().Id // eg 1234 + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique + + _initialized = new Lazy(EnsureInitialized); } + public DatabaseServerMessengerCallbacks Callbacks { get; } + + public GlobalSettings GlobalSettings { get; } + protected ILogger Logger { get; } protected IScopeProvider ScopeProvider { get; } - protected Sql Sql() => _umbracoDatabaseFactory.SqlContext.Sql(); + protected Sql Sql() => ScopeProvider.SqlContext.Sql(); private string DistCacheFilePath => _distCacheFilePath.Value; #region Messenger + // we don't care if there's servers listed or not, + // if distributed call is enabled we will make the call protected override bool RequiresDistributed(ICacheRefresher refresher, MessageType dispatchType) - { - // we don't care if there's servers listed or not, - // if distributed call is enabled we will make the call - return _initialized && DistributedEnabled; - } + => _initialized.Value && DistributedEnabled; protected override void DeliverRemote( ICacheRefresher refresher, @@ -104,7 +119,9 @@ namespace Umbraco.Core.Sync var idsA = ids?.ToArray(); if (GetArrayType(idsA, out var idType) == false) + { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); + } var instructions = RefreshInstruction.GetInstructions(refresher, messageType, idsA, idType, json); @@ -130,17 +147,12 @@ namespace Umbraco.Core.Sync /// /// Boots the messenger. /// - /// - /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. - /// Callers MUST ensure thread-safety. - /// - protected void Boot() + private bool EnsureInitialized() { // weight:10, must release *before* the published snapshot service, because once released // the service will *not* be able to properly handle our notifications anymore const int weight = 10; - var registered = _mainDom.Register( () => { @@ -154,7 +166,7 @@ namespace Umbraco.Core.Sync // properly releasing MainDom - a timeout here means that one refresher // is taking too much time processing, however when it's done we will // not update lastId and stop everything - var idle =_syncIdle.WaitOne(5000); + var idle = _syncIdle.WaitOne(5000); if (idle == false) { Logger.LogWarning("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed."); @@ -163,15 +175,16 @@ namespace Umbraco.Core.Sync weight); if (registered == false) - return; + { + return false; + } ReadLastSynced(); // get _lastId - using (var scope = ScopeProvider.CreateScope()) + + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { EnsureInstructions(scope.Database); // reset _lastId if instructions are missing - Initialize(scope.Database); // boot - - scope.Complete(); + return Initialize(scope.Database); // boot } } @@ -182,14 +195,19 @@ namespace Umbraco.Core.Sync /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. /// Callers MUST ensure thread-safety. /// - private void Initialize(IUmbracoDatabase database) + private bool Initialize(IUmbracoDatabase database) { lock (_locko) { - if (_released) return; + if (_released) + { + return false; + } var coldboot = false; - if (_lastId < 0) // never synced before + + // never synced before + if (_lastId < 0) { // we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new // server and it will need to rebuild it's own caches, eg Lucene or the xml cache file. @@ -201,12 +219,12 @@ namespace Umbraco.Core.Sync } else { - //check for how many instructions there are to process, each row contains a count of the number of instructions contained in each - //row so we will sum these numbers to get the actual count. - var count = database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId}); + // check for how many instructions there are to process, each row contains a count of the number of instructions contained in each + // row so we will sum these numbers to get the actual count. + var count = database.ExecuteScalar("SELECT SUM(instructionCount) FROM umbracoCacheInstruction WHERE id > @lastId", new { lastId = _lastId }); if (count > GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount) { - //too many instructions, proceed to cold boot + // too many instructions, proceed to cold boot Logger.LogWarning( "The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})." + " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id" @@ -224,38 +242,55 @@ namespace Umbraco.Core.Sync // when doing it before, some instructions might run twice - not an issue var maxId = database.ExecuteScalar("SELECT MAX(id) FROM umbracoCacheInstruction"); - //if there is a max currently, or if we've never synced + // if there is a max currently, or if we've never synced if (maxId > 0 || _lastId < 0) + { SaveLastSynced(maxId); + } // execute initializing callbacks if (Callbacks.InitializingCallbacks != null) + { foreach (var callback in Callbacks.InitializingCallbacks) + { callback(); + } + } } - _initialized = true; + return true; } } /// /// Synchronize the server (throttled). /// - public void Sync() + public override void Sync() { + if (!_initialized.Value) + { + return; + } + lock (_locko) { if (_syncing) + { return; + } - //Don't continue if we are released + // Don't continue if we are released if (_released) + { return; + } if ((DateTime.UtcNow - _lastSync) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenSyncOperations) + { return; + } - //Set our flag and the lock to be in it's original state (i.e. it can be awaited) + // Set our flag and the lock to be in it's original state (i.e. it can be awaited) _syncing = true; _syncIdle.Reset(); _lastSync = DateTime.UtcNow; @@ -268,7 +303,7 @@ namespace Umbraco.Core.Sync { ProcessDatabaseInstructions(scope.Database); - //Check for pruning throttling + // Check for pruning throttling if (_released || (DateTime.UtcNow - _lastPruned) <= GlobalSettings.DatabaseServerMessenger.TimeBetweenPruneOperations) { scope.Complete(); @@ -292,7 +327,7 @@ namespace Umbraco.Core.Sync { lock (_locko) { - //We must reset our flag and signal any waiting locks + // We must reset our flag and signal any waiting locks _syncing = false; } @@ -306,9 +341,6 @@ namespace Umbraco.Core.Sync /// /// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded. /// - /// - /// Returns the number of processed instructions - /// private void ProcessDatabaseInstructions(IUmbracoDatabase database) { // NOTE @@ -324,7 +356,7 @@ namespace Umbraco.Core.Sync .Where(dto => dto.Id > _lastId) .OrderBy(dto => dto.Id); - //only retrieve the top 100 (just in case there's tons) + // only retrieve the top 100 (just in case there's tons) // even though MaxProcessingInstructionCount is by default 1000 we still don't want to process that many // rows in one request thread since each row can contain a ton of instructions (until 7.5.5 in which case // a row can only contain MaxProcessingInstructionCount) @@ -337,15 +369,15 @@ namespace Umbraco.Core.Sync var lastId = 0; - //tracks which ones have already been processed to avoid duplicates + // tracks which ones have already been processed to avoid duplicates var processed = new HashSet(); - //It would have been nice to do this in a Query instead of Fetch using a data reader to save + // It would have been nice to do this in a Query instead of Fetch using a data reader to save // some memory however we cannot do that because inside of this loop the cache refreshers are also // performing some lookups which cannot be done with an active reader open foreach (var dto in database.Fetch(topSql)) { - //If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot + // If this flag gets set it means we're shutting down! In this case, we need to exit asap and cannot // continue processing anything otherwise we'll hold up the app domain shutdown if (_released) { @@ -377,10 +409,10 @@ namespace Umbraco.Core.Sync var instructionBatch = GetAllInstructions(jsonA); - //process as per-normal + // process as per-normal var success = ProcessDatabaseInstructions(instructionBatch, dto, processed, ref lastId); - //if they couldn't be all processed (i.e. we're shutting down) then exit + // if they couldn't be all processed (i.e. we're shutting down) then exit if (success == false) { Logger.LogInformation("The current batch of instructions was not processed, app is shutting down"); @@ -425,11 +457,11 @@ namespace Umbraco.Core.Sync //} catch (Exception ex) { - Logger.LogError( - ex, - "DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored", - dto.Id, - dto.Instructions); + Logger.LogError( + ex, + "DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored", + dto.Id, + dto.Instructions); //we cannot throw here because this invalid instruction will just keep getting processed over and over and errors // will be thrown over and over. The only thing we can do is ignore and move on. @@ -509,7 +541,8 @@ namespace Umbraco.Core.Sync /// private void ReadLastSynced() { - if (File.Exists(DistCacheFilePath) == false) return; + if (File.Exists(DistCacheFilePath) == false) + return; var content = File.ReadAllText(DistCacheFilePath); if (int.TryParse(content, out var last)) diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs index f2918ffe96..150f3428a7 100644 --- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs +++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; @@ -346,6 +346,8 @@ namespace Umbraco.Core.Sync DeliverRemote(refresher, messageType, idsA); } + public abstract void Sync(); + //protected virtual void Deliver(ICacheRefresher refresher, object payload) //{ // if (servers == null) throw new ArgumentNullException("servers"); diff --git a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs index af59c27ef2..5db66fdf78 100644 --- a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs +++ b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index ca597a607b..94237ccf3d 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -1,7 +1,6 @@ using System.Linq; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Configuration; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; diff --git a/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs index 719d014296..6f6e0d0c0e 100644 --- a/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.PublishedCache.NuCache/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Scoping; diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index 9b09f7c562..394884a0db 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -10,6 +11,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Web.Common.DependencyInjection; @@ -42,16 +44,15 @@ namespace Umbraco.Tests.Integration { var testHelper = new TestHelper(); - var hostBuilder = new HostBuilder() + IHostBuilder hostBuilder = new HostBuilder() .ConfigureServices((hostContext, services) => { - var webHostEnvironment = testHelper.GetWebHostEnvironment(); + IWebHostEnvironment webHostEnvironment = testHelper.GetWebHostEnvironment(); services.AddSingleton(testHelper.DbProviderFactoryCreator); services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); // Add it! - - var typeLoader = services.AddTypeLoader( + TypeLoader typeLoader = services.AddTypeLoader( GetType().Assembly, webHostEnvironment, testHelper.GetHostingEnvironment(), @@ -60,9 +61,13 @@ namespace Umbraco.Tests.Integration hostContext.Configuration, testHelper.Profiler); - var builder = new UmbracoBuilder(services, hostContext.Configuration, typeLoader, + var builder = new UmbracoBuilder( + services, + hostContext.Configuration, + typeLoader, testHelper.ConsoleLoggerFactory); - builder.Services.AddUnique(AppCaches.NoCache); + + builder.Services.AddUnique(AppCaches.NoCache); builder.AddConfiguration() .AddUmbracoCore() .Build(); @@ -70,15 +75,14 @@ namespace Umbraco.Tests.Integration services.AddRouting(); // LinkGenerator }); - var host = await hostBuilder.StartAsync(); + IHost host = await hostBuilder.StartAsync(); var app = new ApplicationBuilder(host.Services); app.UseUmbracoCore(); - // assert results - var runtimeState = app.ApplicationServices.GetRequiredService(); - var mainDom = app.ApplicationServices.GetRequiredService(); + IRuntimeState runtimeState = app.ApplicationServices.GetRequiredService(); + IMainDom mainDom = app.ApplicationServices.GetRequiredService(); Assert.IsTrue(mainDom.IsMainDom); Assert.IsNull(runtimeState.BootFailedException); @@ -97,10 +101,7 @@ namespace Umbraco.Tests.Integration IsComposed = true; } - public static void Reset() - { - IsComposed = false; - } + public static void Reset() => IsComposed = false; public static bool IsComposed { get; private set; } } @@ -108,24 +109,16 @@ namespace Umbraco.Tests.Integration public class MyComponent : IComponent { public static bool IsInit { get; private set; } + public static bool IsTerminated { get; private set; } private readonly ILogger _logger; - public MyComponent(ILogger logger) - { - _logger = logger; - } + public MyComponent(ILogger logger) => _logger = logger; - public void Initialize() - { - IsInit = true; - } + public void Initialize() => IsInit = true; - public void Terminate() - { - IsTerminated = true; - } + public void Terminate() => IsTerminated = true; public static void Reset() { @@ -134,6 +127,4 @@ namespace Umbraco.Tests.Integration } } } - - } diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs index 39d74f8869..1aeaec1bca 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs @@ -1,4 +1,4 @@ -using Moq; +using Moq; using NUnit.Framework; using System; using System.Collections.Generic; @@ -22,10 +22,10 @@ using Umbraco.Core.Sync; using Umbraco.Core.WebAssets; using Umbraco.Examine; using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web.Compose; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.Scheduling; using Umbraco.Web.Search; +using Umbraco.Infrastructure.Cache; namespace Umbraco.Tests.Integration.Testing { @@ -38,11 +38,12 @@ namespace Umbraco.Tests.Integration.Testing /// public class IntegrationTestComposer : ComponentComposer { + // TODO: Kill this and only enable using ext methods what we need (first we need to kill composers) + public override void Compose(IUmbracoBuilder builder) { base.Compose(builder); - builder.Components().Remove(); builder.Services.AddUnique(); builder.Services.AddUnique(factory => Mock.Of()); @@ -65,7 +66,6 @@ namespace Umbraco.Tests.Integration.Testing /// Used to register a replacement for where the file sources are the ones within the netcore project so /// we don't need to copy files /// - /// private ILocalizedTextService GetLocalizedTextService(IServiceProvider factory) { var globalSettings = factory.GetRequiredService>(); @@ -153,6 +153,8 @@ namespace Umbraco.Tests.Integration.Testing { } + + public void Sync() { } } } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index 11f4095f53..556dedee14 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs @@ -335,6 +335,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping : base(false) { } + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { throw new NotImplementedException(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs index 80bf464c31..6b5af1e1e2 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs @@ -2171,6 +2171,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public LocalServerMessenger() : base(false) { } + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { } diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs index 76f96ead05..d6db3c09f6 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using NPoco; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Persistence; diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs index 0b0f3120d0..40e70d9b5d 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -18,6 +18,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; using Umbraco.Core.IO; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs index 1023e47dfa..6211711202 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs @@ -127,12 +127,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache internal class TestServerMessenger : IServerMessenger { // Used for tests - public List IntIdsRefreshed = new List(); - public List GuidIdsRefreshed = new List(); - public List IntIdsRemoved = new List(); - public List PayloadsRemoved = new List(); - public List PayloadsRefreshed = new List(); - public int CountOfFullRefreshes = 0; + public List IntIdsRefreshed { get; } = new List(); + public List GuidIdsRefreshed { get; } = new List(); + public List IntIdsRemoved { get; } = new List(); + public List PayloadsRemoved { get; } = new List(); + public List PayloadsRefreshed { get; } = new List(); + public int CountOfFullRefreshes { get; private set; } = 0; public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) { @@ -156,6 +156,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) => GuidIdsRefreshed.AddRange(guidIds); public void PerformRefreshAll(ICacheRefresher refresher) => CountOfFullRefreshes++; + + public void Sync() { } } internal class TestServerRegistrar : IServerRegistrar diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs index 6ea56792e2..5187f83375 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs @@ -16,7 +16,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe [TestFixture] public class InstructionProcessTaskTests { - private Mock _mockDatabaseServerMessenger; + private Mock _mockDatabaseServerMessenger; [TestCase(RuntimeLevel.Boot)] [TestCase(RuntimeLevel.Install)] @@ -45,7 +45,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe var mockLogger = new Mock>(); - _mockDatabaseServerMessenger = new Mock(); + _mockDatabaseServerMessenger = new Mock(); var settings = new GlobalSettings(); diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index 1800abc8a8..f18aacf18b 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using System; using System.Linq; using System.Threading; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index edcd199463..7392537e39 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -6,6 +6,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index e4b3721892..3387f424dd 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -6,9 +6,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 797b1c2be9..af0dab8e14 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 9262c72dfa..912d1e4995 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -25,6 +25,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.Common; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 9332dc894a..a8d017e3cb 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -26,6 +26,7 @@ using Umbraco.Web.Mvc; using Umbraco.Web.Runtime; using Umbraco.Web.WebApi; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs index 50b1597cca..de8ddfd201 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -1,10 +1,10 @@ using NUnit.Framework; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Tests.Common; using Umbraco.Tests.Testing; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs index 4c658379cd..649f63f09e 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs @@ -2,8 +2,8 @@ using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index aaf3b0de96..a18d12351f 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -5,8 +5,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; diff --git a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs index af2ffad6e5..46d67eb9bd 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -13,6 +12,7 @@ using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Routing { diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index e663996d60..b1851694bc 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.IO; diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 76a947f63a..4f424f4bb0 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 6814210cc4..51c306a864 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -299,6 +300,8 @@ namespace Umbraco.Tests.Scoping : base(false) { } + public override void Sync() { } + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { throw new NotImplementedException(); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index cab74e22e4..103d361fc5 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -6,8 +6,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index e91c2fdf4d..bea5deb10c 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -38,6 +38,7 @@ using Umbraco.Tests.Common.Builders; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.TestHelpers { diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 8c7b9a00e2..302e1198a8 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -32,6 +32,7 @@ using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web.WebApi; using Umbraco.Tests.Common; using Umbraco.Core.Security; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.TestHelpers { diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 288a309374..4da5ba7189 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -43,6 +43,7 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 59b453cc5b..61b5141856 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -2,9 +2,9 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index cdc2bfed00..52e1c3a5a3 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -12,7 +12,6 @@ using System.Web.Http; using Moq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; @@ -37,6 +36,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Persistance.SqlCe; using Umbraco.Web.Routing; +using Umbraco.Core.DependencyInjection; namespace Umbraco.Tests.Web.Controllers { diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs index e9bf69f2c0..d933d00d68 100644 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -1,7 +1,6 @@ using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 39a3eb3dce..1d11f32916 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -31,9 +31,11 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.HostedServices; using Umbraco.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Infrastructure.Runtime; +using Umbraco.Web.Cache; using Umbraco.Web.Common.ApplicationModels; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.DependencyInjection; @@ -50,6 +52,9 @@ namespace Umbraco.Web.Common.DependencyInjection /// public static class UmbracoBuilderExtensions { + /// + /// Creates an and registers basic Umbraco services + /// public static IUmbracoBuilder AddUmbraco( this IServiceCollection services, IWebHostEnvironment webHostEnvironment, @@ -65,6 +70,8 @@ namespace Umbraco.Web.Common.DependencyInjection throw new ArgumentNullException(nameof(config)); } + // TODO: Should some/all of these registrations be moved directly into UmbracoBuilder? + IHostingEnvironment tempHostingEnvironment = GetTemporaryHostingEnvironment(webHostEnvironment, config); var loggingDir = tempHostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.LogFiles); diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs index f2babdb07c..6bfa402154 100644 --- a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -9,7 +9,6 @@ using Umbraco.Web.Common.Install; using Umbraco.Core.Hosting; using System.Linq.Expressions; using Umbraco.Web.Common.Controllers; -using System.Linq; namespace Umbraco.Extensions { diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index f42fc274f0..4161cafd91 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -7,10 +7,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Serilog; using Serilog.Extensions.Hosting; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Runtime; diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs index 3c00b0d3bc..eac3e058c2 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs index a23f880e7e..758125b425 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Web.Common.Middleware; diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs index 1058192034..9a097f688b 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs @@ -1,6 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Smidge.FileProcessors; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Core.Runtime; diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs index a40b29aea2..2a4b85a0df 100644 --- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs +++ b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs @@ -1,4 +1,3 @@ -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; using Umbraco.Extensions; diff --git a/src/Umbraco.Web/UmbracoBuilderExtensions.cs b/src/Umbraco.Web/UmbracoBuilderExtensions.cs index bb6fe29c93..d9eea6b5ea 100644 --- a/src/Umbraco.Web/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web/UmbracoBuilderExtensions.cs @@ -1,6 +1,5 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; using Umbraco.Core.DependencyInjection; using Umbraco.Web.Routing; From 1f6297ad6bb75b0b2dd74d2808885e234465592c Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 11:46:17 +1100 Subject: [PATCH 02/16] Moves some services 'up' to Core, moves core DI registrations 'up' to UmbracoBuilder, moves Composing ext to DependencyInjection namespaces as UmbracoBuilder ext --- .../ServiceCollectionExtensions.cs | 2 +- .../DependencyInjection/UmbracoBuilder.cs | 111 ++++++++++++ .../EmailNotificationMethod.cs | 1 + src/Umbraco.Core/{ => Mail}/IEmailSender.cs | 4 +- src/Umbraco.Core/{ => Mail}/ISmsSender.cs | 4 +- .../Mail/NotImplementedEmailSender.cs | 12 ++ .../Mail}/NotImplementedSmsSender.cs | 4 +- .../{ => PublishedCache}/ITagQuery.cs | 0 ...uginsManifestWatcherNotificationHandler.cs | 3 +- .../Runtime/EssentialDirectoryCreator.cs | 3 +- .../Runtime/MainDomSemaphoreLock.cs | 6 +- .../{Implement => }/DashboardService.cs | 0 .../Services}/InstallationService.cs | 4 +- src/Umbraco.Core/Services/UpgradeService.cs | 5 +- .../CompositionExtensions/Installer.cs | 36 ---- .../UmbracoBuilder.CoreServices.cs | 166 +++++------------- .../UmbracoBuilder.DistributedCache.cs | 18 ++ .../UmbracoBuilder.FileSystems.cs} | 16 +- .../UmbracoBuilder.Installer.cs | 36 ++++ .../UmbracoBuilder.MappingProfiles.cs} | 12 +- .../UmbracoBuilder.Repositories.cs} | 11 +- .../UmbracoBuilder.Services.cs} | 27 ++- src/Umbraco.Infrastructure/EmailSender.cs | 1 + .../Manifest/ManifestParser.cs | 2 +- .../Media/ImageDimensionExtractor.cs | 11 +- .../Packaging/PackageInstallation.cs | 13 +- .../Services/Implement/NotificationService.cs | 1 + src/Umbraco.Tests.Integration/RuntimeTests.cs | 1 - .../Umbraco.Core/IO/FileSystemsTests.cs | 14 +- .../TestHelpers/TestHelper.cs | 1 + src/Umbraco.Tests/TestHelpers/TestHelper.cs | 1 + src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 8 +- .../Controllers/AuthenticationController.cs | 1 + .../Controllers/UsersController.cs | 1 + .../Trees/PartialViewsTreeController.cs | 5 +- .../UmbracoBuilderExtensions.cs | 54 +----- .../Runtime/AspNetCoreComposer.cs | 4 +- 37 files changed, 301 insertions(+), 298 deletions(-) rename src/Umbraco.Core/{ => Mail}/IEmailSender.cs (78%) rename src/Umbraco.Core/{ => Mail}/ISmsSender.cs (84%) create mode 100644 src/Umbraco.Core/Mail/NotImplementedEmailSender.cs rename src/{Umbraco.Infrastructure => Umbraco.Core/Mail}/NotImplementedSmsSender.cs (90%) rename src/Umbraco.Core/{ => PublishedCache}/ITagQuery.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Runtime/AppPluginsManifestWatcherNotificationHandler.cs (96%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Runtime/EssentialDirectoryCreator.cs (96%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Runtime/MainDomSemaphoreLock.cs (92%) rename src/Umbraco.Core/Services/{Implement => }/DashboardService.cs (100%) rename src/{Umbraco.Infrastructure/Services/Implement/Implement => Umbraco.Core/Services}/InstallationService.cs (87%) delete mode 100644 src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs rename src/Umbraco.Infrastructure/{Composing/CompositionExtensions/FileSystems.cs => DependencyInjection/UmbracoBuilder.FileSystems.cs} (87%) create mode 100644 src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs rename src/Umbraco.Infrastructure/{Composing/CompositionExtensions/CoreMappingProfiles.cs => DependencyInjection/UmbracoBuilder.MappingProfiles.cs} (79%) rename src/Umbraco.Infrastructure/{Composing/CompositionExtensions/Repositories.cs => DependencyInjection/UmbracoBuilder.Repositories.cs} (91%) rename src/Umbraco.Infrastructure/{Composing/CompositionExtensions/Services.cs => DependencyInjection/UmbracoBuilder.Services.cs} (89%) diff --git a/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs index 51ff6b705f..97e70da9be 100644 --- a/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs @@ -51,7 +51,7 @@ namespace Umbraco.Core.DependencyInjection where TService : class => services.Replace(ServiceDescriptor.Singleton(instance)); - public static IServiceCollection AddLazySupport(this IServiceCollection services) + internal static IServiceCollection AddLazySupport(this IServiceCollection services) { services.Replace(ServiceDescriptor.Transient(typeof(Lazy<>), typeof(LazyResolve<>))); return services; diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 1c05695429..11b035bb73 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -3,12 +3,36 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Mail; +using Umbraco.Core.Manifest; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Runtime; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Core.Sync; +using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.Editors; +using Umbraco.Web.Features; +using Umbraco.Web.Install; +using Umbraco.Web.Models.PublishedContent; +using Umbraco.Web.Routing; +using Umbraco.Web.Services; +using Umbraco.Web.Templates; namespace Umbraco.Core.DependencyInjection { @@ -79,6 +103,93 @@ namespace Umbraco.Core.DependencyInjection // Register as singleton to allow injection everywhere. Services.AddSingleton(p => p.GetService); Services.AddSingleton(); + + Services.AddLazySupport(); + + Services.AddUnique(); + + Services.AddUnique(factory => + { + IHostingEnvironment hostingEnvironment = factory.GetRequiredService(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return new IOHelperLinux(hostingEnvironment); + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return new IOHelperOSX(hostingEnvironment); + } + + return new IOHelperWindows(hostingEnvironment); + }); + + Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); + Services.AddUnique(factory => factory.GetRequiredService().RequestCache); + Services.AddUnique(); + Services.AddUnique(); + + this.AddNotificationHandler(); + + Services.AddSingleton(); + this.AddNotificationHandler(); + + Services.AddUnique(); + + // by default, register a noop factory + Services.AddUnique(); + + Services.AddUnique(); + Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); + + Services.AddUnique(); + + Services.AddUnique(); + + // will be injected in controllers when needed to invoke rest endpoints on Our + Services.AddUnique(); + Services.AddUnique(); + + // Grid config is not a real config file as we know them + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + // register properties fallback + Services.AddUnique(); + + Services.AddUnique(); + + // register published router + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + + // register distributed cache + Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); + + // register the http context and umbraco context accessors + // we *should* use the HttpContextUmbracoContextAccessor, however there are cases when + // we have no http context, eg when booting Umbraco or in background threads, so instead + // let's use an hybrid accessor that can fall back to a ThreadStatic context. + Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); } } } diff --git a/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index d29f3ccb0b..ad92886ecd 100644 --- a/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Core/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.HealthCheck; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Infrastructure.HealthCheck; diff --git a/src/Umbraco.Core/IEmailSender.cs b/src/Umbraco.Core/Mail/IEmailSender.cs similarity index 78% rename from src/Umbraco.Core/IEmailSender.cs rename to src/Umbraco.Core/Mail/IEmailSender.cs index aab944e04d..3862d0e717 100644 --- a/src/Umbraco.Core/IEmailSender.cs +++ b/src/Umbraco.Core/Mail/IEmailSender.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Umbraco.Core.Models; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// Simple abstraction to send an email message diff --git a/src/Umbraco.Core/ISmsSender.cs b/src/Umbraco.Core/Mail/ISmsSender.cs similarity index 84% rename from src/Umbraco.Core/ISmsSender.cs rename to src/Umbraco.Core/Mail/ISmsSender.cs index f296a2ea9b..a2ff054c48 100644 --- a/src/Umbraco.Core/ISmsSender.cs +++ b/src/Umbraco.Core/Mail/ISmsSender.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// Service to send an SMS diff --git a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs new file mode 100644 index 0000000000..bb8d787cbf --- /dev/null +++ b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Mail +{ + internal class NotImplementedEmailSender : IEmailSender + { + public Task SendAsync(EmailMessage message) + => throw new NotImplementedException("To send an Email ensure IEmailSender is implemented with a custom implementation"); + } +} diff --git a/src/Umbraco.Infrastructure/NotImplementedSmsSender.cs b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs similarity index 90% rename from src/Umbraco.Infrastructure/NotImplementedSmsSender.cs rename to src/Umbraco.Core/Mail/NotImplementedSmsSender.cs index ffc33373d0..16c3d04711 100644 --- a/src/Umbraco.Infrastructure/NotImplementedSmsSender.cs +++ b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs @@ -1,7 +1,7 @@ -using System; +using System; using System.Threading.Tasks; -namespace Umbraco.Core +namespace Umbraco.Core.Mail { /// /// An that throws diff --git a/src/Umbraco.Core/ITagQuery.cs b/src/Umbraco.Core/PublishedCache/ITagQuery.cs similarity index 100% rename from src/Umbraco.Core/ITagQuery.cs rename to src/Umbraco.Core/PublishedCache/ITagQuery.cs diff --git a/src/Umbraco.Infrastructure/Runtime/AppPluginsManifestWatcherNotificationHandler.cs b/src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs similarity index 96% rename from src/Umbraco.Infrastructure/Runtime/AppPluginsManifestWatcherNotificationHandler.cs rename to src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs index b67f41136a..5f219ac51f 100644 --- a/src/Umbraco.Infrastructure/Runtime/AppPluginsManifestWatcherNotificationHandler.cs +++ b/src/Umbraco.Core/Runtime/AppPluginsManifestWatcherNotificationHandler.cs @@ -2,12 +2,11 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; -using Umbraco.Core; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.Manifest; -namespace Umbraco.Infrastructure.Runtime +namespace Umbraco.Core.Runtime { /// /// Starts monitoring AppPlugins directory during debug runs, to restart site when a plugin manifest changes. diff --git a/src/Umbraco.Infrastructure/Runtime/EssentialDirectoryCreator.cs b/src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs similarity index 96% rename from src/Umbraco.Infrastructure/Runtime/EssentialDirectoryCreator.cs rename to src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs index 5543662464..92ad5808b3 100644 --- a/src/Umbraco.Infrastructure/Runtime/EssentialDirectoryCreator.cs +++ b/src/Umbraco.Core/Runtime/EssentialDirectoryCreator.cs @@ -1,13 +1,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; -using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -namespace Umbraco.Infrastructure.Runtime +namespace Umbraco.Core.Runtime { public class EssentialDirectoryCreator : INotificationHandler { diff --git a/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs similarity index 92% rename from src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs rename to src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs index eed13f5060..74dea6742c 100644 --- a/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs +++ b/src/Umbraco.Core/Runtime/MainDomSemaphoreLock.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -29,7 +29,7 @@ namespace Umbraco.Core.Runtime _logger = logger; } - //WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread + // WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread public Task ListenAsync() => _signal.WaitOneAsync(); public Task AcquireLockAsync(int millisecondsTimeout) @@ -44,7 +44,7 @@ namespace Umbraco.Core.Runtime // if more than 1 instance reach that point, one will get the lock // and the other one will timeout, which is accepted - //This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset. + // This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset. try { _lockRelease = _systemLock.Lock(millisecondsTimeout); diff --git a/src/Umbraco.Core/Services/Implement/DashboardService.cs b/src/Umbraco.Core/Services/DashboardService.cs similarity index 100% rename from src/Umbraco.Core/Services/Implement/DashboardService.cs rename to src/Umbraco.Core/Services/DashboardService.cs diff --git a/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs b/src/Umbraco.Core/Services/InstallationService.cs similarity index 87% rename from src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs rename to src/Umbraco.Core/Services/InstallationService.cs index a1f74e0862..6e283a61d7 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs +++ b/src/Umbraco.Core/Services/InstallationService.cs @@ -1,8 +1,8 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -namespace Umbraco.Core.Services.Implement +namespace Umbraco.Core.Services { public class InstallationService : IInstallationService { diff --git a/src/Umbraco.Core/Services/UpgradeService.cs b/src/Umbraco.Core/Services/UpgradeService.cs index ead5270b41..b36eac7789 100644 --- a/src/Umbraco.Core/Services/UpgradeService.cs +++ b/src/Umbraco.Core/Services/UpgradeService.cs @@ -1,10 +1,9 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Semver; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -using Umbraco.Core.Services; -namespace Umbraco.Core +namespace Umbraco.Core.Services { public class UpgradeService : IUpgradeService { diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs deleted file mode 100644 index dc3b1e2481..0000000000 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Web.Install; -using Umbraco.Web.Install.InstallSteps; -using Umbraco.Web.Install.Models; - -namespace Umbraco.Web.Composing.CompositionExtensions -{ - public static class Installer - { - public static IUmbracoBuilder ComposeInstaller(this IUmbracoBuilder builder) - { - // register the installer steps - - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - // TODO: Add these back once we have a compatible Starter kit - // composition.Services.AddScoped(); - // composition.Services.AddScoped(); - // composition.Services.AddScoped(); - - builder.Services.AddScoped(); - - builder.Services.AddTransient(); - builder.Services.AddUnique(); - - return builder; - } - } -} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index e150f0cdba..b4fd03350a 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -1,18 +1,16 @@ -using System; +using System.Runtime.InteropServices; using Examine; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dashboards; using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Dictionary; -using Umbraco.Core.Events; +using Umbraco.Core.Hosting; using Umbraco.Core.Install; +using Umbraco.Core.Mail; using Umbraco.Core.Manifest; using Umbraco.Core.Media; using Umbraco.Core.Migrations; @@ -20,16 +18,14 @@ using Umbraco.Core.Migrations.Install; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Packaging; +using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; -using Umbraco.Core.Security; using Umbraco.Core.Serialization; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; -using Umbraco.Core.Sync; using Umbraco.Core.Templates; using Umbraco.Examine; using Umbraco.Infrastructure.Examine; @@ -37,10 +33,8 @@ using Umbraco.Infrastructure.Media; using Umbraco.Infrastructure.Runtime; using Umbraco.Web; using Umbraco.Web.Actions; -using Umbraco.Web.Cache; using Umbraco.Web.ContentApps; using Umbraco.Web.Editors; -using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; using Umbraco.Web.HealthCheck.NotificationMethods; using Umbraco.Web.Install; @@ -54,8 +48,6 @@ using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Search; using Umbraco.Web.Sections; -using Umbraco.Web.Services; -using Umbraco.Web.Templates; using Umbraco.Web.Trees; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; @@ -66,7 +58,7 @@ namespace Umbraco.Infrastructure.DependencyInjection /* * TODO: Many of these things are not "Core" services and are probably not required to run - * + * * This should be split up: * - Distributed Cache * - BackOffice @@ -83,19 +75,25 @@ namespace Umbraco.Infrastructure.DependencyInjection * - Front End */ + /// + /// Adds all core Umbraco services required to run which may be replaced later in the pipeline + /// public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder) { - builder.AddNotificationHandler(); + builder.AddMainDom(); - builder.Services.AddSingleton(); - builder.AddNotificationHandler(); + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => factory.GetRequiredService().CreateDatabase()); + builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); + builder.Services.AddUnique(); + builder.Services.AddUnique(); // composers builder - .ComposeRepositories() - .ComposeServices() - .ComposeCoreMappingProfiles() - .ComposeFileSystems(); + .AddRepositories() + .AddServices() + .AddCoreMappingProfiles() + .AddFileSystems(); // register persistence mappers - required by database factory so needs to be done here // means the only place the collection can be modified is in a runtime - afterwards it @@ -110,7 +108,6 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.Services.AddUnique(); // register database builder // *not* a singleton, don't want to keep it around @@ -146,41 +143,6 @@ namespace Umbraco.Infrastructure.DependencyInjection // references to media item/s builder.DataValueReferenceFactories(); - // register a server registrar, by default it's the db registrar - builder.Services.AddUnique(f => - { - var globalSettings = f.GetRequiredService>().Value; - - // TODO: we still register the full IServerMessenger because - // even on 1 single server we can have 2 concurrent app domains - var singleServer = globalSettings.DisableElectionForSingleServer; - return singleServer - ? (IServerRegistrar)new SingleServerRegistrar(f.GetRequiredService()) - : new DatabaseServerRegistrar( - new Lazy(f.GetRequiredService)); - }); - - // by default we'll use the database server messenger with default options (no callbacks), - // this will be overridden by the db thing in the corresponding components in the web - // project - builder.Services.AddUnique(factory - => new DatabaseServerMessenger( - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService>(), - factory.GetRequiredService(), - true, - new DatabaseServerMessengerCallbacks(), - factory.GetRequiredService(), - factory.GetRequiredService(), - factory.GetRequiredService>() - )); - - builder.CacheRefreshers() - .Add(() => builder.TypeLoader.GetCacheRefreshers()); - builder.PackageActions() .Add(() => builder.TypeLoader.GetPackageActions()); @@ -197,43 +159,20 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(factory => new MigrationBuilder(factory)); - // by default, register a noop factory - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.SetCultureDictionaryFactory(); - builder.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); - builder.Services.AddUnique(); - // register the published snapshot accessor - the "current" published snapshot is in the umbraco context builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.Services.AddUnique(); - // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards builder.Dashboards() .Add(builder.TypeLoader.GetTypes()); - // will be injected in controllers when needed to invoke rest endpoints on Our - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Grid config is not a real config file as we know them - builder.Services.AddUnique(); - // Config manipulator builder.Services.AddUnique(); - // register the umbraco context factory - // composition.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddUnique(); @@ -254,15 +193,8 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.MediaUrlProviders() .Append(); - builder.Services.AddUnique(); - - // register properties fallback - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Actions() .Add(() => builder.TypeLoader.GetTypes()); @@ -311,9 +243,6 @@ namespace Umbraco.Infrastructure.DependencyInjection .Append() .Append(); - // register published router - builder.Services.AddUnique(); - // register *all* checks, except those marked [HideFromTypeFinder] of course builder.Services.AddUnique(); builder.HealthChecks() @@ -325,12 +254,14 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); builder.ContentFinders() + // all built-in finders in the correct order, // devs can then modify this list on application startup .Append() .Append() .Append() - //.Append() // disabled, this is an odd finder + + // .Append() // disabled, this is an odd finder .Append() .Append(); @@ -339,26 +270,13 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.SearchableTrees() .Add(() => builder.TypeLoader.GetTypes()); - // replace some services - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); + // replace builder.Services.AddUnique(); - builder.Services.AddUnique(); builder.Services.AddUnique(); - // register distributed cache - builder.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); - builder.Services.AddScoped(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); builder.Services.AddScoped(factory => { @@ -366,14 +284,6 @@ namespace Umbraco.Infrastructure.DependencyInjection return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); }); - builder.Services.AddUnique(); - - // register the http context and umbraco context accessors - // we *should* use the HttpContextUmbracoContextAccessor, however there are cases when - // we have no http context, eg when booting Umbraco or in background threads, so instead - // let's use an hybrid accessor that can fall back to a ThreadStatic context. - builder.Services.AddUnique(); - // register accessors for cultures builder.Services.AddUnique(); @@ -389,17 +299,33 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); - builder.Services.AddUnique(factory => new LegacyPasswordSecurity()); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.Services.AddUnique(); return builder; } + + private static IUmbracoBuilder AddMainDom(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + + builder.Services.AddUnique(factory => + { + var globalSettings = factory.GetRequiredService>().Value; + var connectionStrings = factory.GetRequiredService>().Value; + var hostingEnvironment = factory.GetRequiredService(); + + var dbCreator = factory.GetRequiredService(); + var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var loggerFactory = factory.GetRequiredService(); + + return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false + ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment) + : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); + }); + + return builder; + } } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index 4970df2b87..23e927df97 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -1,8 +1,11 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; +using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; using Umbraco.Infrastructure.Cache; @@ -29,6 +32,21 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.SetServerMessenger(); builder.AddNotificationHandler(); + // TODO: We don't need server registrar anymore + // register a server registrar, by default it's the db registrar + builder.Services.AddUnique(f => + { + var globalSettings = f.GetRequiredService>().Value; + + // TODO: we still register the full IServerMessenger because + // even on 1 single server we can have 2 concurrent app domains + var singleServer = globalSettings.DisableElectionForSingleServer; + return singleServer + ? (IServerRegistrar)new SingleServerRegistrar(f.GetRequiredService()) + : new DatabaseServerRegistrar( + new Lazy(f.GetRequiredService)); + }); + builder.CacheRefreshers() .Add(() => builder.TypeLoader.GetCacheRefreshers()); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs similarity index 87% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs index 4c8caa89b8..5c61fd2c60 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs @@ -1,17 +1,15 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; -using Umbraco.Core.Strings; -using Umbraco.Infrastructure.DependencyInjection; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { - internal static class FileSystems + public static partial class UmbracoBuilderExtensions { /* * HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM @@ -35,16 +33,16 @@ namespace Umbraco.Core.Composing.CompositionExtensions * */ - public static IUmbracoBuilder ComposeFileSystems(this IUmbracoBuilder builder) + internal static IUmbracoBuilder AddFileSystems(this IUmbracoBuilder builder) { // register FileSystems, which manages all filesystems // it needs to be registered (not only the interface) because it provides additional // functionality eg for scoping, and is injected in the scope provider - whereas the // interface is really for end-users to get access to filesystems. - builder.Services.AddUnique(factory => factory.CreateInstance(factory)); + builder.Services.AddUnique(factory => factory.CreateInstance(factory)); // register IFileSystems, which gives access too all filesystems - builder.Services.AddUnique(factory => factory.GetRequiredService()); + builder.Services.AddUnique(factory => factory.GetRequiredService()); // register the scheme for media paths builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs new file mode 100644 index 0000000000..bcdead6fd0 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Web.Install; +using Umbraco.Web.Install.InstallSteps; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds the services for the Umbraco installer + /// + public static IUmbracoBuilder AddInstaller(this IUmbracoBuilder builder) + { + // register the installer steps + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // TODO: Add these back once we have a compatible Starter kit + // composition.Services.AddScoped(); + // composition.Services.AddScoped(); + // composition.Services.AddScoped(); + builder.Services.AddScoped(); + + builder.Services.AddTransient(); + builder.Services.AddUnique(); + + return builder; + } + } +} diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs similarity index 79% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs index c700938534..4974a043b1 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs @@ -4,17 +4,14 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Security; using Umbraco.Web.Models.Mapping; -namespace Umbraco.Core.Composing.CompositionExtensions - +namespace Umbraco.Infrastructure.DependencyInjection { - public static class CoreMappingProfiles + public static partial class UmbracoBuilderExtensions { /// /// Registers the core Umbraco mapper definitions /// - /// - /// - public static IUmbracoBuilder ComposeCoreMappingProfiles(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddCoreMappingProfiles(this IUmbracoBuilder builder) { builder.Services.AddUnique(); @@ -34,8 +31,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions .Add() .Add() .Add() - .Add() - ; + .Add(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs similarity index 91% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs index 05b7371d15..1e32eddb5c 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs @@ -1,15 +1,18 @@ -using Umbraco.Core.DependencyInjection; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { /// /// Composes repositories. /// - internal static class Repositories + public static partial class UmbracoBuilderExtensions { - public static IUmbracoBuilder ComposeRepositories(this IUmbracoBuilder builder) + /// + /// Adds the Umbraco repositories + /// + internal static IUmbracoBuilder AddRepositories(this IUmbracoBuilder builder) { // repositories builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs similarity index 89% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs index b027a99c67..918bdcb941 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Services.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.IO; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; @@ -15,16 +16,15 @@ using Umbraco.Core.Routing; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -namespace Umbraco.Core.Composing.CompositionExtensions +namespace Umbraco.Infrastructure.DependencyInjection { - internal static class Services + public static partial class UmbracoBuilderExtensions { - public static IUmbracoBuilder ComposeServices(this IUmbracoBuilder builder) + /// + /// Adds Umbraco services + /// + internal static IUmbracoBuilder AddServices(this IUmbracoBuilder builder) { - // register a transient messages factory, which will be replaced by the web - // boot manager when running in a web context - builder.Services.AddUnique(); - // register the service context builder.Services.AddUnique(); @@ -59,7 +59,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.Services.AddTransient(SourcesFactory); + builder.Services.AddTransient(SourcesFactory); builder.Services.AddUnique(factory => new LocalizedTextService( factory.GetRequiredService>(), factory.GetRequiredService>())); @@ -82,9 +82,6 @@ namespace Umbraco.Core.Composing.CompositionExtensions /// /// Creates an instance of PackagesRepository for either the ICreatedPackagesRepository or the IInstalledPackagesRepository /// - /// - /// - /// private static PackagesRepository CreatePackageRepository(IServiceProvider factory, string packageRepoFileName) => new PackagesRepository( factory.GetRequiredService(), @@ -106,9 +103,9 @@ namespace Umbraco.Core.Composing.CompositionExtensions { var hostingEnvironment = container.GetRequiredService(); var globalSettings = container.GetRequiredService>().Value; - var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath , "config","lang"))); + var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath, "config", "lang"))); var appPlugins = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins)); - var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config ,"lang"))); + var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config, "lang"))); var pluginLangFolders = appPlugins.Exists == false ? Enumerable.Empty() @@ -117,7 +114,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions .SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly)) .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false)); - //user defined langs that overwrite the default, these should not be used by plugin creators + // user defined langs that overwrite the default, these should not be used by plugin creators var userLangFolders = configLangFolder.Exists == false ? Enumerable.Empty() : configLangFolder diff --git a/src/Umbraco.Infrastructure/EmailSender.cs b/src/Umbraco.Infrastructure/EmailSender.cs index 539adcb971..4c377f1ff1 100644 --- a/src/Umbraco.Infrastructure/EmailSender.cs +++ b/src/Umbraco.Infrastructure/EmailSender.cs @@ -7,6 +7,7 @@ using MimeKit; using MimeKit.Text; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using SmtpClient = MailKit.Net.Smtp.SmtpClient; diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index 15ddcebb7e..d134010104 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs b/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs index 538c559cf6..ad5155e6d2 100644 --- a/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs +++ b/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Drawing; using System.IO; using Umbraco.Core; @@ -18,7 +18,7 @@ namespace Umbraco.Web.Media /// use potentially large amounts of memory. public ImageSize GetDimensions(Stream stream) { - //Try to load with exif + // Try to load with exif try { if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height)) @@ -28,12 +28,13 @@ namespace Umbraco.Web.Media } catch { - //We will just swallow, just means we can't read exif data, we don't want to log an error either + // We will just swallow, just means we can't read exif data, we don't want to log an error either } - //we have no choice but to try to read in via GDI + // we have no choice but to try to read in via GDI try { + // TODO: We should be using ImageSharp for this using (var image = Image.FromStream(stream)) { var fileWidth = image.Width; @@ -43,7 +44,7 @@ namespace Umbraco.Web.Media } catch (Exception) { - //We will just swallow, just means we can't read via GDI, we don't want to log an error either + // We will just swallow, just means we can't read via GDI, we don't want to log an error either } return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize); diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index 4970fc302e..df8a58fc8d 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -17,16 +17,11 @@ namespace Umbraco.Core.Packaging private readonly IPackageActionRunner _packageActionRunner; private readonly DirectoryInfo _applicationRootFolder; + /// - /// Constructor + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, - IHostingEnvironment hostingEnvironment) + public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, IHostingEnvironment hostingEnvironment) { _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index 3e99ca9b4b..653a878ab9 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; +using Umbraco.Core.Mail; namespace Umbraco.Core.Services.Implement { diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index fc2844db24..394884a0db 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -70,7 +70,6 @@ namespace Umbraco.Tests.Integration builder.Services.AddUnique(AppCaches.NoCache); builder.AddConfiguration() .AddUmbracoCore() - .AddNuCache() .Build(); services.AddRouting(); // LinkGenerator diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs index 4474b95584..314a50ce75 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/IO/FileSystemsTests.cs @@ -1,27 +1,17 @@ -using System; +using System; using System.IO; using System.Text; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; -using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.IO { [TestFixture] - [UmbracoTest()] + [UmbracoTest] public class FileSystemsTests : UmbracoIntegrationTest { [Test] diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs index 40e70d9b5d..b23ccc9080 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -23,6 +23,7 @@ using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Mail; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.PublishedContent; diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index bea5deb10c..8c89905c97 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -39,6 +39,7 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Mail; namespace Umbraco.Tests.TestHelpers { diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 4da5ba7189..433ef1de02 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -18,7 +18,6 @@ using Serilog; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; @@ -28,6 +27,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; +using Umbraco.Core.Mail; using Umbraco.Core.Manifest; using Umbraco.Core.Mapping; using Umbraco.Core.Media; @@ -383,7 +383,7 @@ namespace Umbraco.Tests.Testing if (configure == false) return; Builder - .ComposeCoreMappingProfiles(); + .AddCoreMappingProfiles(); } protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IHostingEnvironment hostingEnvironment, ILogger logger, IProfilingLogger profilingLogger, UmbracoTestOptions.TypeLoader option) @@ -452,7 +452,7 @@ namespace Umbraco.Tests.Testing if (withApplication == false) return; // default Datalayer/Repositories/SQL/Database/etc... - Builder.ComposeRepositories(); + Builder.AddRepositories(); Builder.Services.AddUnique(); @@ -497,7 +497,7 @@ namespace Umbraco.Tests.Testing => TestObjects.GetScopeProvider(_loggerFactory, factory.GetService(), factory.GetService())); Builder.Services.AddUnique(factory => (IScopeAccessor)factory.GetRequiredService()); - Builder.ComposeServices(); + Builder.AddServices(); // composition root is doing weird things, fix Builder.Services.AddUnique(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 36e5c2b6fe..502ffbcba2 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Mail; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index 9d7999b9f7..fca8c49004 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -18,6 +18,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; +using Umbraco.Core.Mail; using Umbraco.Core.Mapping; using Umbraco.Core.Media; using Umbraco.Core.Models; diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs index b648bd797f..a5707968ee 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs @@ -1,11 +1,8 @@ -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Umbraco.Core.IO; using Umbraco.Core.Services; -using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Authorization; -using Umbraco.Web.Composing; -using Umbraco.Web.Mvc; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Constants = Umbraco.Core.Constants; diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 1d11f32916..f3109ac2da 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -105,12 +105,16 @@ namespace Umbraco.Web.Common.DependencyInjection throw new ArgumentNullException(nameof(builder)); } - builder.Services.AddLazySupport(); + // Add ASP.NET specific services + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddHostedService(factory => factory.GetRequiredService()); // Add supported databases builder.AddUmbracoSqlCeSupport(); builder.AddUmbracoSqlServerSupport(); + // Must be added here because DbProviderFactories is netstandard 2.1 so cannot exist in Infra for now builder.Services.AddSingleton(factory => new DbProviderFactoryCreator( DbProviderFactories.GetFactory, factory.GetServices(), @@ -118,54 +122,6 @@ namespace Umbraco.Web.Common.DependencyInjection factory.GetServices() )); - builder.Services.AddUnique(factory => - { - var globalSettings = factory.GetRequiredService>().Value; - var connectionStrings = factory.GetRequiredService>().Value; - var hostingEnvironment = factory.GetRequiredService(); - - var dbCreator = factory.GetRequiredService(); - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var loggerFactory = factory.GetRequiredService(); - - return globalSettings.MainDomLock.Equals("SqlMainDomLock") || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbCreator, hostingEnvironment) - : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); - }); - - builder.Services.AddUnique(factory => - { - var hostingEnvironment = factory.GetRequiredService(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return new IOHelperLinux(hostingEnvironment); - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return new IOHelperOSX(hostingEnvironment); - } - - return new IOHelperWindows(hostingEnvironment); - } - - ); - builder.Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); - builder.Services.AddUnique(factory => factory.GetRequiredService().RequestCache); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(factory => factory.GetRequiredService().CreateDatabase()); - builder.Services.AddUnique(factory => factory.GetRequiredService().SqlContext); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddHostedService(factory => factory.GetRequiredService()); - builder.AddCoreInitialServices(); builder.AddComposers(); diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 49dcf5a6db..42352d19f2 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -20,11 +20,11 @@ using Umbraco.Web.Common.Profiler; using Umbraco.Web.Common.Routing; using Umbraco.Web.Common.Security; using Umbraco.Web.Common.Templates; -using Umbraco.Web.Composing.CompositionExtensions; using Umbraco.Web.Macros; using Umbraco.Web.Security; using Umbraco.Web.Templates; using Umbraco.Web.Common.ModelBinders; +using Umbraco.Infrastructure.DependencyInjection; namespace Umbraco.Web.Common.Runtime { @@ -75,7 +75,7 @@ namespace Umbraco.Web.Common.Runtime builder.Services.AddUnique(); //register the install components - builder.ComposeInstaller(); + builder.AddInstaller(); var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); builder.WithCollectionBuilder() From e785ac28a342cdc48b7c01c84385385037be6a58 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 14:29:26 +1100 Subject: [PATCH 03/16] Moves more services and registrations "up", removes AspNetCoreComposer logic and moves to AddWebComponents --- src/Umbraco.Core/Cache/DistributedCache.cs | 10 +- .../UmbracoBuilder.Collections.cs | 186 ++++++++++++++++-- .../UmbracoBuilder.Composers.cs | 26 +++ .../UmbracoBuilder.Configuration.cs | 59 ++++++ .../UmbracoBuilder.Events.cs | 4 +- .../DependencyInjection/UmbracoBuilder.cs | 5 + .../Media/IImageDimensionExtractor.cs | 0 .../Media/ImageSize.cs | 0 .../Media/UploadAutoFillProperties.cs | 0 .../PropertyEditorCollection.cs | 4 +- .../TextStringValueConverter.cs | 0 ...rter.cs => SimpleTinyMceValueConverter.cs} | 4 +- .../TextStringValueConverter.cs | 45 ----- src/Umbraco.Core/Trees/ISearchableTree.cs | 4 +- .../Trees}/SearchableApplicationTree.cs | 4 +- .../Trees}/SearchableTreeCollection.cs | 4 +- .../Trees}/SearchableTreeCollectionBuilder.cs | 5 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../BatchedDatabaseServerMessenger.cs | 5 +- ...abaseServerMessengerNotificationHandler.cs | 4 +- .../UmbracoBuilder.Collections.cs | 73 +------ .../UmbracoBuilder.CoreServices.cs | 122 +----------- .../UmbracoBuilder.DistributedCache.cs | 7 +- .../UmbracoBuilder.Installer.cs | 2 +- .../RteMacroRenderingValueConverter.cs | 4 +- .../Search/UmbracoTreeSearcher.cs | 2 +- .../UmbracoTestServerTestBase.cs | 1 - .../Scoping/ScopedRepositoryTests.cs | 17 +- .../Services/ContentEventsTests.cs | 5 - .../ContentTypeServiceVariantsTests.cs | 2 - .../Services/TrackRelationsTests.cs | 2 - .../PublishedContentTestBase.cs | 2 +- .../Controllers/EntityController.cs | 1 + .../UmbracoBuilderExtensions.cs | 4 +- .../Trees/ContentTreeController.cs | 1 + .../Trees/ContentTypeTreeController.cs | 1 + .../Trees/DataTypeTreeController.cs | 1 + .../Trees/MediaTreeController.cs | 1 + .../Trees/MediaTypeTreeController.cs | 1 + .../Trees/MemberTreeController.cs | 1 + .../Trees/MemberTypeTreeController.cs | 1 + .../Trees/TemplatesTreeController.cs | 1 + .../Trees/TreeControllerBase.cs | 1 + .../UmbracoBuilderExtensions.cs | 130 +++++++----- .../Runtime/AspNetCoreBootFailedComposer.cs | 17 -- .../Runtime/AspNetCoreComposer.cs | 58 ------ .../UmbracoBuilderExtensions.cs | 3 +- 47 files changed, 402 insertions(+), 429 deletions(-) create mode 100644 src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs create mode 100644 src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs rename src/{Umbraco.Infrastructure => Umbraco.Core}/Media/IImageDimensionExtractor.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Media/ImageSize.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Media/UploadAutoFillProperties.cs (100%) rename src/{Umbraco.Infrastructure/PropertyEditors/ValueConverters => Umbraco.Core/PropertyEditors}/TextStringValueConverter.cs (100%) rename src/Umbraco.Core/PropertyEditors/ValueConverters/{TinyMceValueConverter.cs => SimpleTinyMceValueConverter.cs} (95%) delete mode 100644 src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs rename src/{Umbraco.Infrastructure/Search => Umbraco.Core/Trees}/SearchableApplicationTree.cs (92%) rename src/{Umbraco.Infrastructure/Search => Umbraco.Core/Trees}/SearchableTreeCollection.cs (97%) rename src/{Umbraco.Infrastructure/Search => Umbraco.Core/Trees}/SearchableTreeCollectionBuilder.cs (81%) delete mode 100644 src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs diff --git a/src/Umbraco.Core/Cache/DistributedCache.cs b/src/Umbraco.Core/Cache/DistributedCache.cs index 698e97c610..569ff47724 100644 --- a/src/Umbraco.Core/Cache/DistributedCache.cs +++ b/src/Umbraco.Core/Cache/DistributedCache.cs @@ -164,9 +164,15 @@ namespace Umbraco.Web.Cache #endregion // helper method to get an ICacheRefresher by its unique identifier - private ICacheRefresher GetRefresherById(Guid refresherGuid) + private ICacheRefresher GetRefresherById(Guid refresherGuid) { - return _cacheRefreshers[refresherGuid]; + ICacheRefresher refresher = _cacheRefreshers[refresherGuid]; + if (refresher == null) + { + throw new InvalidOperationException($"No cache refresher found with id {refresherGuid}"); + } + + return refresher; } } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs index 35d8ba1025..f6dc6fd6ff 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -1,11 +1,21 @@ +using System.Security.Cryptography; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; using Umbraco.Core.HealthCheck; using Umbraco.Core.Manifest; +using Umbraco.Core.PackageActions; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.Validators; +using Umbraco.Core.Strings; +using Umbraco.Core.Trees; using Umbraco.Web.Actions; using Umbraco.Web.ContentApps; using Umbraco.Web.Dashboards; using Umbraco.Web.Editors; +using Umbraco.Web.HealthCheck; +using Umbraco.Web.HealthCheck.NotificationMethods; +using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Routing; using Umbraco.Web.Sections; using Umbraco.Web.Tour; @@ -17,6 +27,97 @@ namespace Umbraco.Core.DependencyInjection /// public static partial class UmbracoBuilderExtensions { + /// + /// Adds all core collection builders + /// + internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder) + { + builder.CacheRefreshers().Add(() => builder.TypeLoader.GetCacheRefreshers()); + builder.DataEditors().Add(() => builder.TypeLoader.GetDataEditors()); + builder.Actions().Add(() => builder.TypeLoader.GetTypes()); + // register known content apps + builder.ContentApps() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + // all built-in finders in the correct order, + // devs can then modify this list on application startup + builder.ContentFinders() + .Append() + .Append() + .Append() + /*.Append() // disabled, this is an odd finder */ + .Append() + .Append(); + builder.EditorValidators().Add(() => builder.TypeLoader.GetTypes()); + builder.HealthChecks().Add(() => builder.TypeLoader.GetTypes()); + builder.HealthCheckNotificationMethods().Add(() => builder.TypeLoader.GetTypes()); + builder.TourFilters(); + builder.UrlProviders() + .Append() + .Append(); + builder.MediaUrlProviders() + .Append(); + // register back office sections in the order we want them rendered + builder.Sections() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + builder.Components(); + // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards + builder.Dashboards() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(builder.TypeLoader.GetTypes()); + builder.PackageActions().Add(() => builder.TypeLoader.GetPackageActions()); + builder.DataValueReferenceFactories(); + builder.PropertyValueConverters().Append(builder.TypeLoader.GetTypes()); + builder.UrlSegmentProviders().Append(); + builder.ManifestValueValidators() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(); + builder.ManifestFilters(); + builder.MediaUrlGenerators(); + // register OEmbed providers - no type scanning - all explicit opt-in of adding types, IEmbedProvider is not IDiscoverable + builder.OEmbedProviders() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + builder.SearchableTrees().Add(() => builder.TypeLoader.GetTypes()); + } + /// /// Gets the actions collection builder. /// @@ -52,6 +153,9 @@ namespace Umbraco.Core.DependencyInjection public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); + public static HealthCheckNotificationMethodCollectionBuilder HealthCheckNotificationMethods(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + /// /// Gets the TourFilters collection builder. /// @@ -90,18 +194,63 @@ namespace Umbraco.Core.DependencyInjection /// /// The builder. public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add(); + => builder.WithCollectionBuilder(); + + /// + /// Gets the cache refreshers collection builder. + /// + /// The builder. + public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the package actions collection builder. + /// + /// The builder. + internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data editor collection builder. + /// + /// The builder. + public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the data value reference factory collection builder. + /// + /// The builder. + public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the property value converters collection builder. + /// + /// The builder. + public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the url segment providers collection builder. + /// + /// The builder. + public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the validators collection builder. + /// + /// The builder. + internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the manifest filter collection builder. + /// + /// The builder. + public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the content finders collection builder. @@ -109,5 +258,18 @@ namespace Umbraco.Core.DependencyInjection /// The builder. public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice OEmbed Providers collection builder. + /// + /// The builder. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the back office searchable tree collection builder + /// + public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs new file mode 100644 index 0000000000..3479bd74d6 --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Composing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds Umbraco composers for plugins + /// + public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) + { + IEnumerable composerTypes = builder.TypeLoader.GetTypes(); + IEnumerable enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); + new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); + + return builder; + } + } +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs new file mode 100644 index 0000000000..1733536908 --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Add Umbraco configuration services and options + /// + public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder) + { + // Register configuration validators. + builder.Services.AddSingleton, ContentSettingsValidator>(); + builder.Services.AddSingleton, GlobalSettingsValidator>(); + builder.Services.AddSingleton, HealthChecksSettingsValidator>(); + builder.Services.AddSingleton, RequestHandlerSettingsValidator>(); + + // Register configuration sections. + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigActiveDirectory)); + builder.Services.Configure(builder.Config.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigContent)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigCoreDebug)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExceptionFilter)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHealthChecks)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHosting)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigImaging)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExamine)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigKeepAlive)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigLogging)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigMemberPassword)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigNuCache)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRequestHandler)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntime)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigSecurity)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTours)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigUserPassword)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigWebRouting)); + builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigPlugins)); + + return builder; + } + } +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs index a21ae74976..d5090de01b 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Core.Events; namespace Umbraco.Core.DependencyInjection @@ -23,7 +24,8 @@ namespace Umbraco.Core.DependencyInjection where TNotification : INotification { // Register the handler as transient. This ensures that anything can be injected into it. - builder.Services.AddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); + // TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 + builder.Services.TryAddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); return builder; } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 11b035bb73..32eed6d78d 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -20,6 +20,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Mail; using Umbraco.Core.Manifest; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Runtime; using Umbraco.Core.Security; using Umbraco.Core.Services; @@ -130,6 +131,7 @@ namespace Umbraco.Core.DependencyInjection Services.AddUnique(); Services.AddUnique(); + this.AddAllCoreCollectionBuilders(); this.AddNotificationHandler(); Services.AddSingleton(); @@ -190,6 +192,9 @@ namespace Umbraco.Core.DependencyInjection Services.AddUnique(); Services.AddUnique(); Services.AddUnique(); + + Services.AddUnique(); + Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Media/IImageDimensionExtractor.cs b/src/Umbraco.Core/Media/IImageDimensionExtractor.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/IImageDimensionExtractor.cs rename to src/Umbraco.Core/Media/IImageDimensionExtractor.cs diff --git a/src/Umbraco.Infrastructure/Media/ImageSize.cs b/src/Umbraco.Core/Media/ImageSize.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/ImageSize.cs rename to src/Umbraco.Core/Media/ImageSize.cs diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs similarity index 100% rename from src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs rename to src/Umbraco.Core/Media/UploadAutoFillProperties.cs diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs index 2149ece02a..a3c02aeb0d 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorCollection.cs @@ -1,11 +1,9 @@ -using System.Linq; +using System.Linq; using Umbraco.Core.Composing; using Umbraco.Core.Manifest; namespace Umbraco.Core.PropertyEditors { - - public class PropertyEditorCollection : BuilderCollectionBase { public PropertyEditorCollection(DataEditorCollection dataEditors, IManifestParser manifestParser) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/TextStringValueConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TextStringValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/TextStringValueConverter.cs diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs similarity index 95% rename from src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs index 51471f6da7..64ecba5c7c 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/SimpleTinyMceValueConverter.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Strings; @@ -8,7 +8,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters /// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used. /// [DefaultPropertyValueConverter] - public class TinyMceValueConverter : PropertyValueConverterBase + public class SimpleTinyMceValueConverter : PropertyValueConverterBase { public override bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs deleted file mode 100644 index 7caa9a90cc..0000000000 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Linq; -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Core.PropertyEditors.ValueConverters -{ - [DefaultPropertyValueConverter] - public class TextStringValueConverter : PropertyValueConverterBase - { - private static readonly string[] PropertyTypeAliases = - { - Constants.PropertyEditors.Aliases.TextBox, - Constants.PropertyEditors.Aliases.TextArea - }; - - public override bool IsConverter(IPublishedPropertyType propertyType) - => PropertyTypeAliases.Contains(propertyType.EditorAlias); - - public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (string); - - public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => PropertyCacheLevel.Element; - - public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - { - // in xml a string is: string - // in the database a string is: string - // default value is: null - return source; - } - - public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - // source should come from ConvertSource and be a string (or null) already - return inter ?? string.Empty; - } - - public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - { - // source should come from ConvertSource and be a string (or null) already - return inter; - } - } -} diff --git a/src/Umbraco.Core/Trees/ISearchableTree.cs b/src/Umbraco.Core/Trees/ISearchableTree.cs index 3d82d548c8..8f31c2c6ab 100644 --- a/src/Umbraco.Core/Trees/ISearchableTree.cs +++ b/src/Umbraco.Core/Trees/ISearchableTree.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Umbraco.Core.Composing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Web.Trees +namespace Umbraco.Core.Trees { public interface ISearchableTree : IDiscoverable { diff --git a/src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs b/src/Umbraco.Core/Trees/SearchableApplicationTree.cs similarity index 92% rename from src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs rename to src/Umbraco.Core/Trees/SearchableApplicationTree.cs index 346f106b84..ad6fb7f43f 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableApplicationTree.cs +++ b/src/Umbraco.Core/Trees/SearchableApplicationTree.cs @@ -1,6 +1,4 @@ -using Umbraco.Web.Trees; - -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableApplicationTree { diff --git a/src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs b/src/Umbraco.Core/Trees/SearchableTreeCollection.cs similarity index 97% rename from src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs rename to src/Umbraco.Core/Trees/SearchableTreeCollection.cs index 5c251a857d..e562b763d4 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableTreeCollection.cs +++ b/src/Umbraco.Core/Trees/SearchableTreeCollection.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Umbraco.Core; @@ -6,7 +6,7 @@ using Umbraco.Core.Composing; using Umbraco.Web.Services; using Umbraco.Web.Trees; -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableTreeCollection : BuilderCollectionBase { diff --git a/src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs b/src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs similarity index 81% rename from src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs rename to src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs index a5e940b4a6..7922cf36ad 100644 --- a/src/Umbraco.Infrastructure/Search/SearchableTreeCollectionBuilder.cs +++ b/src/Umbraco.Core/Trees/SearchableTreeCollectionBuilder.cs @@ -1,8 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Composing; -using Umbraco.Web.Trees; -namespace Umbraco.Web.Search +namespace Umbraco.Core.Trees { public class SearchableTreeCollectionBuilder : LazyCollectionBuilderBase { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 24b2fae683..263621aed7 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -19,6 +19,7 @@ + diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index bafb537db6..131aac23f7 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -9,11 +9,9 @@ using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; using Umbraco.Core.Sync; -using Umbraco.Web.Routing; namespace Umbraco.Web { @@ -28,6 +26,9 @@ namespace Umbraco.Web private readonly IRequestCache _requestCache; private readonly IRequestAccessor _requestAccessor; + /// + /// Initializes a new instance of the class. + /// public BatchedDatabaseServerMessenger( IMainDom mainDom, IScopeProvider scopeProvider, diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs index b0921f7698..43527b5486 100644 --- a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -47,7 +47,7 @@ namespace Umbraco.Infrastructure.Cache // Hence we hook up a one-off task on an HTTP request to ensure this is retrieved, which caches the value and makes it available // for the hosted services to use when the HTTP request is not available. _requestAccessor.RouteAttempt += EnsureApplicationUrlOnce; - _requestAccessor.EndRequest += UmbracoModule_EndRequest; + _requestAccessor.EndRequest += EndRequest; Startup(); @@ -88,6 +88,6 @@ namespace Umbraco.Infrastructure.Cache /// /// Clear the batch on end request /// - private void UmbracoModule_EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.FlushBatch(); + private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.FlushBatch(); } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs index 28bed7b363..4da9c93fb3 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs @@ -5,8 +5,8 @@ using Umbraco.Core.PackageActions; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Strings; +using Umbraco.Core.Trees; using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Search; namespace Umbraco.Infrastructure.DependencyInjection { @@ -15,82 +15,11 @@ namespace Umbraco.Infrastructure.DependencyInjection /// public static partial class UmbracoBuilderExtensions { - /// - /// Gets the cache refreshers collection builder. - /// - /// The builder. - public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - /// /// Gets the mappers collection builder. /// /// The builder. public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); - - /// - /// Gets the package actions collection builder. - /// - /// The builder. - internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data editor collection builder. - /// - /// The builder. - public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the data value reference factory collection builder. - /// - /// The builder. - public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the property value converters collection builder. - /// - /// The builder. - public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the url segment providers collection builder. - /// - /// The builder. - public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the validators collection builder. - /// - /// The builder. - internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the manifest filter collection builder. - /// - /// The builder. - public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the backoffice OEmbed Providers collection builder. - /// - /// The builder. - public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the back office searchable tree collection builder - /// - /// - /// - public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); } } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index b4fd03350a..b5c76aad83 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -27,6 +27,7 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Core.Templates; +using Umbraco.Core.Trees; using Umbraco.Examine; using Umbraco.Infrastructure.Examine; using Umbraco.Infrastructure.Media; @@ -49,7 +50,6 @@ using Umbraco.Web.Routing; using Umbraco.Web.Search; using Umbraco.Web.Sections; using Umbraco.Web.Trees; -using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; namespace Umbraco.Infrastructure.DependencyInjection { @@ -116,47 +116,18 @@ namespace Umbraco.Infrastructure.DependencyInjection // register manifest parser, will be injected in collection builders where needed builder.Services.AddUnique(); - // register our predefined validators - builder.ManifestValueValidators() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add(); - // register the manifest filter collection builder (collection is empty by default) builder.ManifestFilters(); - // properties and parameters derive from data editors - builder.DataEditors() - .Add(() => builder.TypeLoader.GetDataEditors()); - builder.MediaUrlGenerators() .Add() .Add(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Used to determine if a datatype/editor should be storing/tracking - // references to media item/s - builder.DataValueReferenceFactories(); - - builder.PackageActions() - .Add(() => builder.TypeLoader.GetPackageActions()); - - builder.PropertyValueConverters() - .Append(builder.TypeLoader.GetTypes()); - builder.Services.AddUnique(); builder.Services.AddUnique(factory => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); - builder.UrlSegmentProviders() - .Append(); - builder.Services.AddUnique(factory => new MigrationBuilder(factory)); builder.Services.AddUnique(); @@ -166,10 +137,6 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); - // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards - builder.Dashboards() - .Add(builder.TypeLoader.GetTypes()); - // Config manipulator builder.Services.AddUnique(); @@ -177,99 +144,22 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); // both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be - // discovered when CoreBootManager configures the converters. We HAVE to remove one of them - // here because there cannot be two converters for one property editor - and we want the full - // RteMacroRenderingValueConverter that converts macros, etc. So remove TinyMceValueConverter. - // (the limited one, defined in Core, is there for tests) - same for others + // discovered when CoreBootManager configures the converters. We will remove the basic one defined + // in core so that the more enhanced version is active. builder.PropertyValueConverters() - .Remove() - .Remove() - .Remove(); - - builder.UrlProviders() - .Append() - .Append(); - - builder.MediaUrlProviders() - .Append(); + .Remove(); builder.Services.AddUnique(); - builder.Actions() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.EditorValidators() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.TourFilters(); - builder.Services.AddUnique(); - // register OEmbed providers - no type scanning - all explicit opt-in of adding types - // note: IEmbedProvider is not IDiscoverable - think about it if going for type scanning - builder.OEmbedProviders() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - // register back office sections in the order we want them rendered - builder.Sections() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - // register known content apps - builder.ContentApps() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - // register *all* checks, except those marked [HideFromTypeFinder] of course builder.Services.AddUnique(); - builder.HealthChecks() - .Add(() => builder.TypeLoader.GetTypes()); - - builder.WithCollectionBuilder() - .Add(() => builder.TypeLoader.GetTypes()); - + builder.Services.AddUnique(); - builder.ContentFinders() - - // all built-in finders in the correct order, - // devs can then modify this list on application startup - .Append() - .Append() - .Append() - - // .Append() // disabled, this is an odd finder - .Append() - .Append(); - builder.Services.AddScoped(); - builder.SearchableTrees() - .Add(() => builder.TypeLoader.GetTypes()); - // replace builder.Services.AddUnique(); @@ -303,6 +193,8 @@ namespace Umbraco.Infrastructure.DependencyInjection builder.Services.AddUnique(); + builder.AddInstaller(); + return builder; } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index 23e927df97..8be46d38fb 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -26,7 +26,7 @@ namespace Umbraco.Infrastructure.DependencyInjection /// public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder) { - // NOTE: the `DistributedCache` is registered in AddCoreInitialServices since it's a core service + // NOTE: the `DistributedCache` is registered in UmbracoBuilder since it's a core service builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); builder.SetServerMessenger(); @@ -34,7 +34,7 @@ namespace Umbraco.Infrastructure.DependencyInjection // TODO: We don't need server registrar anymore // register a server registrar, by default it's the db registrar - builder.Services.AddUnique(f => + builder.Services.AddUnique(f => { var globalSettings = f.GetRequiredService>().Value; @@ -47,9 +47,6 @@ namespace Umbraco.Infrastructure.DependencyInjection new Lazy(f.GetRequiredService)); }); - builder.CacheRefreshers() - .Add(() => builder.TypeLoader.GetCacheRefreshers()); - builder.Services.AddUnique(); return builder; } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs index bcdead6fd0..e5bdd844d8 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Installer.cs @@ -11,7 +11,7 @@ namespace Umbraco.Infrastructure.DependencyInjection /// /// Adds the services for the Umbraco installer /// - public static IUmbracoBuilder AddInstaller(this IUmbracoBuilder builder) + internal static IUmbracoBuilder AddInstaller(this IUmbracoBuilder builder) { // register the installer steps builder.Services.AddScoped(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 7fe202ed4c..d0713b46ff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Text; using HtmlAgilityPack; using Umbraco.Core; @@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters /// used dynamically. /// [DefaultPropertyValueConverter] - public class RteMacroRenderingValueConverter : TinyMceValueConverter + public class RteMacroRenderingValueConverter : SimpleTinyMceValueConverter { private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IMacroRenderer _macroRenderer; diff --git a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs index ecaf7354ca..a2955dfef5 100644 --- a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs @@ -8,11 +8,11 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Examine; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; -using Umbraco.Web.Trees; namespace Umbraco.Web.Search { diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index ef3735032e..017b0ddb45 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -154,7 +154,6 @@ namespace Umbraco.Tests.Integration.TestServerTest mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly); }) .AddWebServer() - .AddNuCache() .Build(); } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index 556dedee14..e42fd7dbf1 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -14,7 +11,6 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Sync; -using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; @@ -29,15 +25,12 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping private DistributedCacheBinder _distributedCacheBinder; private IUserService UserService => GetRequiredService(); - private ILocalizationService LocalizationService => GetRequiredService(); - private IServerMessenger ServerMessenger => GetRequiredService(); - private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); - protected override void CustomTestSetup(IUmbracoBuilder builder) - { - builder.AddNuCache(); - builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IServerMessenger), typeof(LocalServerMessenger))); - } + private ILocalizationService LocalizationService => GetRequiredService(); + + private IServerMessenger ServerMessenger { get; } = new LocalServerMessenger(); + + private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); protected override AppCaches GetAppCaches() { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs index 6b5af1e1e2..44459550d2 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs @@ -5,16 +5,13 @@ using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Sync; -using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; -using Umbraco.Web.BackOffice.DependencyInjection; using Umbraco.Web.Cache; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services @@ -54,8 +51,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services ContentTypeService.Save(_contentType); } - protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddNuCache(); - [TearDown] public void TearDownTest() { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index 010f680ad1..b52609ce89 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -38,8 +38,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private ILocalizationService LocalizationService => GetRequiredService(); - protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddNuCache(); - protected override void BeforeHostStart(IHost host) { base.BeforeHostStart(host); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs index e4095c1d33..e6a8104355 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs @@ -19,8 +19,6 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services Boot = true)] public class TrackRelationsTests : UmbracoIntegrationTestWithContent { - protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddNuCache(); - private IMediaTypeService MediaTypeService => GetRequiredService(); private IMediaService MediaService => GetRequiredService(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index aa8fc26bd8..ec8e55e2bf 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -36,7 +36,7 @@ namespace Umbraco.Tests.PublishedContent Builder.WithCollectionBuilder() .Clear() .Append() - .Append() + .Append() .Append(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index b2a6300cc9..219ca694e8 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -31,6 +31,7 @@ using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; using Umbraco.Web.Security; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Controllers { diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index e8c6171f01..30e6bdcbc7 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -2,6 +2,7 @@ using System; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.DependencyInjection; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Web.BackOffice.Authorization; using Umbraco.Web.BackOffice.Security; @@ -32,8 +33,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddWebServer() .AddPreviewSupport() .AddHostedServices() - .AddHttpClients() - .AddNuCache(); + .AddDistributedCache(); /// /// Adds Umbraco back office authentication requirements diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 16dd446d49..404ebfdb3a 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -22,6 +22,7 @@ using Microsoft.Extensions.Options; using Umbraco.Web.Trees; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 8b5286bdd2..25c48b94bd 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index ab2bfdb8d4..30389fb1be 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -16,6 +16,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index ece4013d0b..d284624999 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -22,6 +22,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index cd64e23067..424a0b2451 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -15,6 +15,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs index 4ebd8f7cc5..378a90da83 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs @@ -22,6 +22,7 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; +using Umbraco.Core.Trees; namespace Umbraco.Web.BackOffice.Trees { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs index be400bef39..8a8fe7b11e 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Attributes; diff --git a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs index 361875a41b..eb08dbe629 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Services; +using Umbraco.Core.Trees; using Umbraco.Extensions; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Filters; diff --git a/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs index e469cd4a25..ad4266e5e5 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TreeControllerBase.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.Trees; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Filters; diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index f3109ac2da..29e3820637 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Data.SqlClient; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Microsoft.AspNetCore.Builder; @@ -25,22 +26,39 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; +using Umbraco.Core.Security; using Umbraco.Extensions; using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.HostedServices; using Umbraco.Infrastructure.HostedServices.ServerRegistration; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Infrastructure.Runtime; +using Umbraco.Net; using Umbraco.Web.Cache; using Umbraco.Web.Common.ApplicationModels; using Umbraco.Web.Common.AspNetCore; +using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.DependencyInjection; +using Umbraco.Web.Common.Install; +using Umbraco.Web.Common.Lifetime; +using Umbraco.Web.Common.Macros; +using Umbraco.Web.Common.Middleware; +using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.Common.Profiler; +using Umbraco.Web.Common.Routing; +using Umbraco.Web.Common.Security; +using Umbraco.Web.Common.Templates; +using Umbraco.Web.Macros; +using Umbraco.Web.Security; using Umbraco.Web.Telemetry; +using Umbraco.Web.Templates; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Web.Common.DependencyInjection @@ -123,62 +141,13 @@ namespace Umbraco.Web.Common.DependencyInjection )); builder.AddCoreInitialServices(); + + // TODO: This should be a separate call to opt-in to plugins builder.AddComposers(); return builder; } - /// - /// Adds Umbraco composers for plugins - /// - public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) - { - IEnumerable composerTypes = builder.TypeLoader.GetTypes(); - IEnumerable enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); - new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); - - return builder; - } - - /// - /// Add Umbraco configuration services and options - /// - public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder) - { - // Register configuration validators. - builder.Services.AddSingleton, ContentSettingsValidator>(); - builder.Services.AddSingleton, GlobalSettingsValidator>(); - builder.Services.AddSingleton, HealthChecksSettingsValidator>(); - builder.Services.AddSingleton, RequestHandlerSettingsValidator>(); - - // Register configuration sections. - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigActiveDirectory)); - builder.Services.Configure(builder.Config.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigContent)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigCoreDebug)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExceptionFilter)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigGlobal)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHealthChecks)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigHosting)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigImaging)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigExamine)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigKeepAlive)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigLogging)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigMemberPassword)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigNuCache)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRequestHandler)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntime)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigSecurity)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTours)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigTypeFinder)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigUserPassword)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigWebRouting)); - builder.Services.Configure(builder.Config.GetSection(Core.Constants.Configuration.ConfigPlugins)); - - return builder; - } - /// /// Add Umbraco hosted services /// @@ -195,8 +164,7 @@ namespace Umbraco.Web.Common.DependencyInjection return builder; } - // TODO: Not sure this needs to exist and/or be public? - public static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) + private static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) { builder.Services.AddHttpClient(); return builder; @@ -241,6 +209,9 @@ namespace Umbraco.Web.Common.DependencyInjection return builder; } + /// + /// Adds all web based services required for Umbraco to run + /// public static IUmbracoBuilder AddWebComponents(this IUmbracoBuilder builder) { // Add service session @@ -257,6 +228,59 @@ namespace Umbraco.Web.Common.DependencyInjection builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); builder.Services.AddUmbracoImageSharp(builder.Config); + // AspNetCore specific services + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // Our own netcore implementations + builder.Services.AddMultipleUnique(); + + builder.Services.AddUnique(); + + // The umbraco request lifetime + builder.Services.AddMultipleUnique(); + + // Password hasher + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddTransient(); + builder.Services.AddUnique(); + + builder.Services.AddMultipleUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // register the umbraco context factory + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.WithCollectionBuilder() + .Add(umbracoApiControllerTypes); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.AddNuCache(); + builder.AddHttpClients(); + return builder; } diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs deleted file mode 100644 index 758125b425..0000000000 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Web.Common.Middleware; - -namespace Umbraco.Web.Common.Runtime -{ - /// - /// Executes if the boot fails to ensure critical services are registered - /// - public class AspNetCoreBootFailedComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 42352d19f2..34a8b7583a 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -35,63 +35,5 @@ namespace Umbraco.Web.Common.Runtime [ComposeBefore(typeof(ICoreComposer))] public class AspNetCoreComposer : ComponentComposer, IComposer { - public override void Compose(IUmbracoBuilder builder) - { - base.Compose(builder); - - // AspNetCore specific services - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // Our own netcore implementations - builder.Services.AddMultipleUnique(); - - builder.Services.AddUnique(); - - // The umbraco request lifetime - builder.Services.AddMultipleUnique(); - - // Password hasher - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddTransient(); - builder.Services.AddUnique(); - - builder.Services.AddMultipleUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // register the umbraco context factory - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - //register the install components - builder.AddInstaller(); - - var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); - builder.WithCollectionBuilder() - .Add(umbracoApiControllerTypes); - - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } } } diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index f495c09d3c..5762a5fb69 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core.DependencyInjection; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Web.Website.Controllers; using Umbraco.Web.Website.Routing; @@ -35,7 +36,7 @@ namespace Umbraco.Web.Website.DependencyInjection builder.Services.AddScoped(); builder.Services.AddSingleton(); - builder.AddNuCache(); + builder.AddDistributedCache(); return builder; } From 307ef4c1e070193aae9c40dec562dbe371eef8ef Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 14:44:42 +1100 Subject: [PATCH 04/16] Removes IBatchedDatabaseServerMessenger, renames methods of IServerMessenger --- src/Umbraco.Core/Cache/DistributedCache.cs | 16 +++++++------- .../Sync/DatabaseServerMessengerCallbacks.cs | 4 ++-- .../Sync/IBatchedDatabaseServerMessenger.cs | 12 ----------- src/Umbraco.Core/Sync/IServerMessenger.cs | 21 ++++++++++++------- .../BatchedDatabaseServerMessenger.cs | 7 ++++--- ...abaseServerMessengerNotificationHandler.cs | 6 +++--- .../HostedServices/ScheduledPublishing.cs | 4 ++-- .../Sync/ServerMessengerBase.cs | 21 ++++++++++--------- .../Testing/IntegrationTestComposer.cs | 18 +++++++++------- .../Scoping/ScopedRepositoryTests.cs | 2 ++ .../Services/ContentEventsTests.cs | 2 ++ .../DistributedCache/DistributedCacheTests.cs | 18 +++++++++------- src/Umbraco.Tests/Scoping/ScopedXmlTests.cs | 4 +++- 13 files changed, 70 insertions(+), 65 deletions(-) delete mode 100644 src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs diff --git a/src/Umbraco.Core/Cache/DistributedCache.cs b/src/Umbraco.Core/Cache/DistributedCache.cs index 569ff47724..7ad9f9569f 100644 --- a/src/Umbraco.Core/Cache/DistributedCache.cs +++ b/src/Umbraco.Core/Cache/DistributedCache.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), getNumericId, instances); @@ -61,7 +61,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == default(int)) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), id); } @@ -75,7 +75,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == Guid.Empty) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), id); } @@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || payload == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), payload); } @@ -97,7 +97,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || payloads == null) return; - _serverMessenger.PerformRefresh( + _serverMessenger.QueueRefresh( GetRefresherById(refresherGuid), payloads.ToArray()); } @@ -125,7 +125,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty) return; - _serverMessenger.PerformRefreshAll( + _serverMessenger.QueueRefreshAll( GetRefresherById(refresherGuid)); } @@ -138,7 +138,7 @@ namespace Umbraco.Web.Cache { if (refresherGuid == Guid.Empty || id == default(int)) return; - _serverMessenger.PerformRemove( + _serverMessenger.QueueRemove( GetRefresherById(refresherGuid), id); } @@ -155,7 +155,7 @@ namespace Umbraco.Web.Cache /// public void Remove(Guid refresherGuid, Func getNumericId, params T[] instances) { - _serverMessenger.PerformRemove( + _serverMessenger.QueueRemove( GetRefresherById(refresherGuid), getNumericId, instances); diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs b/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs index 7438762295..f7dafac7a6 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessengerCallbacks.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; namespace Umbraco.Core.Sync { /// - /// Holds a list of callbacks associated with implementations of . + /// Holds a list of callbacks associated with implementations of . /// public class DatabaseServerMessengerCallbacks { diff --git a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs deleted file mode 100644 index 02859ff6f0..0000000000 --- a/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Umbraco.Core.Sync -{ - /// - /// An implementation that works by storing messages in the database. - /// - public interface IBatchedDatabaseServerMessenger : IServerMessenger - { - // TODO: We only ever use IBatchedDatabaseServerMessenger so just combine these interfaces - - void FlushBatch(); - } -} diff --git a/src/Umbraco.Core/Sync/IServerMessenger.cs b/src/Umbraco.Core/Sync/IServerMessenger.cs index a6c5b5d755..df2d665057 100644 --- a/src/Umbraco.Core/Sync/IServerMessenger.cs +++ b/src/Umbraco.Core/Sync/IServerMessenger.cs @@ -14,12 +14,17 @@ namespace Umbraco.Core.Sync /// void Sync(); + /// + /// Called to send/commit the queued messages created with the Perform methods + /// + void SendMessages(); + /// /// Notifies the distributed cache, for a specified . /// /// The ICacheRefresher. /// The notification content. - void PerformRefresh(ICacheRefresher refresher, TPayload[] payload); + void QueueRefresh(ICacheRefresher refresher, TPayload[] payload); /// /// Notifies the distributed cache of specified item invalidation, for a specified . @@ -28,7 +33,7 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The invalidated items. - void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances); + void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances); /// /// Notifies the distributed cache of specified item invalidation, for a specified . @@ -37,7 +42,7 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The invalidated items. - void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances); + void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances); /// /// Notifies all servers of specified items removal, for a specified . @@ -46,33 +51,33 @@ namespace Umbraco.Core.Sync /// The ICacheRefresher. /// A function returning the unique identifier of items. /// The removed items. - void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances); + void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances); /// /// Notifies all servers of specified items removal, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the removed items. - void PerformRemove(ICacheRefresher refresher, params int[] numericIds); + void QueueRemove(ICacheRefresher refresher, params int[] numericIds); /// /// Notifies all servers of specified items invalidation, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the invalidated items. - void PerformRefresh(ICacheRefresher refresher, params int[] numericIds); + void QueueRefresh(ICacheRefresher refresher, params int[] numericIds); /// /// Notifies all servers of specified items invalidation, for a specified . /// /// The ICacheRefresher. /// The unique identifiers of the invalidated items. - void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds); + void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds); /// /// Notifies all servers of a global invalidation for a specified . /// /// The ICacheRefresher. - void PerformRefreshAll(ICacheRefresher refresher); + void QueueRefreshAll(ICacheRefresher refresher); } } diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index 131aac23f7..caba831aff 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web /// /// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls /// - public class BatchedDatabaseServerMessenger : DatabaseServerMessenger, IBatchedDatabaseServerMessenger + public class BatchedDatabaseServerMessenger : DatabaseServerMessenger { private readonly IRequestCache _requestCache; private readonly IRequestAccessor _requestAccessor; @@ -58,7 +58,7 @@ namespace Umbraco.Web BatchMessage(refresher, messageType, idsA, arrayType, json); } - public void FlushBatch() + public override void SendMessages() { var batch = GetBatch(false); if (batch == null) return; @@ -66,13 +66,14 @@ namespace Umbraco.Web var instructions = batch.SelectMany(x => x.Instructions).ToArray(); batch.Clear(); - //Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount + // Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount using (var scope = ScopeProvider.CreateScope()) { foreach (var instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) { WriteInstructions(scope, instructionsBatch); } + scope.Complete(); } diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs index 43527b5486..c8d8c81ab1 100644 --- a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -15,7 +15,7 @@ namespace Umbraco.Infrastructure.Cache /// public sealed class DatabaseServerMessengerNotificationHandler : INotificationHandler { - private readonly IBatchedDatabaseServerMessenger _messenger; + private readonly IServerMessenger _messenger; private readonly IRequestAccessor _requestAccessor; private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IDistributedCacheBinder _distributedCacheBinder; @@ -35,7 +35,7 @@ namespace Umbraco.Infrastructure.Cache _databaseFactory = databaseFactory; _distributedCacheBinder = distributedCacheBinder; _logger = logger; - _messenger = serverMessenger as IBatchedDatabaseServerMessenger; + _messenger = serverMessenger; } /// @@ -88,6 +88,6 @@ namespace Umbraco.Infrastructure.Cache /// /// Clear the batch on end request /// - private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.FlushBatch(); + private void EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.SendMessages(); } } diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs index 4c235255c2..bd73310c29 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs @@ -123,9 +123,9 @@ namespace Umbraco.Infrastructure.HostedServices finally { // If running on a temp context, we have to flush the messenger - if (contextReference.IsRoot && _serverMessenger is IBatchedDatabaseServerMessenger m) + if (contextReference.IsRoot) { - m.FlushBatch(); + _serverMessenger.SendMessages(); } } } diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs index 150f3428a7..dfba90291b 100644 --- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs +++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs @@ -55,7 +55,7 @@ namespace Umbraco.Core.Sync #region IServerMessenger - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); if (payload == null) throw new ArgumentNullException(nameof(payload)); @@ -72,7 +72,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByJson, json: jsonPayload); } - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -83,7 +83,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByInstance, getId, instances); } - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -94,7 +94,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshByInstance, getId, instances); } - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -105,7 +105,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RemoveByInstance, getId, instances); } - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -114,7 +114,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RemoveById, numericIds.Cast()); } - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -123,7 +123,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshById, numericIds.Cast()); } - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -132,7 +132,7 @@ namespace Umbraco.Core.Sync Deliver(refresher, MessageType.RefreshById, guidIds.Cast()); } - public void PerformRefreshAll(ICacheRefresher refresher) + public void QueueRefreshAll(ICacheRefresher refresher) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -346,8 +346,6 @@ namespace Umbraco.Core.Sync DeliverRemote(refresher, messageType, idsA); } - public abstract void Sync(); - //protected virtual void Deliver(ICacheRefresher refresher, object payload) //{ // if (servers == null) throw new ArgumentNullException("servers"); @@ -367,5 +365,8 @@ namespace Umbraco.Core.Sync //} #endregion + + public abstract void Sync(); + public abstract void SendMessages(); } } diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs index 1aeaec1bca..842a2a8a34 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs @@ -114,47 +114,49 @@ namespace Umbraco.Tests.Integration.Testing public NoopServerMessenger() { } - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { } - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) { } - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) { } - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) { } - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) { } - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) { } - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) { } - public void PerformRefreshAll(ICacheRefresher refresher) + public void QueueRefreshAll(ICacheRefresher refresher) { } public void Sync() { } + + public void SendMessages() { } } } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index e42fd7dbf1..0a1e46274b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs @@ -328,6 +328,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping : base(false) { } + public override void SendMessages() { } + public override void Sync() { } protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs index 44459550d2..68ec7fcf5f 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs @@ -2166,6 +2166,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public LocalServerMessenger() : base(false) { } + public override void SendMessages() { } + public override void Sync() { } protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs index 6211711202..706ca94e71 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs @@ -134,30 +134,32 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache public List PayloadsRefreshed { get; } = new List(); public int CountOfFullRefreshes { get; private set; } = 0; - public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + public void QueueRefresh(ICacheRefresher refresher, TPayload[] payload) { // doing nothing } public void PerformRefresh(ICacheRefresher refresher, string jsonPayload) => PayloadsRefreshed.Add(jsonPayload); - public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRefreshed.AddRange(instances.Select(getNumericId)); + public void QueueRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRefreshed.AddRange(instances.Select(getNumericId)); - public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) => GuidIdsRefreshed.AddRange(instances.Select(getGuidId)); + public void QueueRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) => GuidIdsRefreshed.AddRange(instances.Select(getGuidId)); public void PerformRemove(ICacheRefresher refresher, string jsonPayload) => PayloadsRemoved.Add(jsonPayload); - public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRemoved.AddRange(instances.Select(getNumericId)); + public void QueueRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) => IntIdsRemoved.AddRange(instances.Select(getNumericId)); - public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) => IntIdsRemoved.AddRange(numericIds); + public void QueueRemove(ICacheRefresher refresher, params int[] numericIds) => IntIdsRemoved.AddRange(numericIds); - public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) => IntIdsRefreshed.AddRange(numericIds); + public void QueueRefresh(ICacheRefresher refresher, params int[] numericIds) => IntIdsRefreshed.AddRange(numericIds); - public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) => GuidIdsRefreshed.AddRange(guidIds); + public void QueueRefresh(ICacheRefresher refresher, params Guid[] guidIds) => GuidIdsRefreshed.AddRange(guidIds); - public void PerformRefreshAll(ICacheRefresher refresher) => CountOfFullRefreshes++; + public void QueueRefreshAll(ICacheRefresher refresher) => CountOfFullRefreshes++; public void Sync() { } + + public void SendMessages() { } } internal class TestServerRegistrar : IServerRegistrar diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 51c306a864..b4009d6f3e 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Xml; using Microsoft.Extensions.DependencyInjection; @@ -300,6 +300,8 @@ namespace Umbraco.Tests.Scoping : base(false) { } + public override void SendMessages() { } + public override void Sync() { } protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) From 91486bbede4dc15c949704141b4a34d612301ed6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 16:35:59 +1100 Subject: [PATCH 05/16] Removes IServerRegistrar, new IServerRoleAccessor, removes more composers, moves more to ext, --- .../UmbracoBuilder.Composers.cs | 5 +- .../DependencyInjection/UmbracoBuilder.cs | 21 ++++++++ src/Umbraco.Core/Diagnostics/NoopMarchal.cs | 9 ++++ .../IUmbracoApplicationLifetime.cs | 11 ++-- .../IUmbracoApplicationLifetimeManager.cs | 8 +++ .../NoopApplicationShutdownRegistry.cs | 8 +++ .../NoopUmbracoApplicationLifetimeManager.cs | 7 +++ .../InstallSteps/StarterKitInstallStep.cs | 2 +- .../{VoidProfiler.cs => NoopProfiler.cs} | 4 +- src/Umbraco.Core/Manifest/ManifestWatcher.cs | 2 +- .../Services/IServerRegistrationService.cs | 10 +--- .../Sync/DatabaseServerRegistrar.cs | 43 ---------------- .../Sync/ElectedServerRoleAccessor.cs | 29 +++++++++++ src/Umbraco.Core/Sync/IServerRegistrar.cs | 21 -------- src/Umbraco.Core/Sync/IServerRoleAccessor.cs | 15 ++++++ .../Sync/SingleServerRegistrar.cs | 44 ---------------- .../Sync/SingleServerRoleAccessor.cs | 19 +++++++ .../BatchedDatabaseServerMessenger.cs | 2 +- .../UmbracoBuilder.CoreServices.cs | 51 +++++++------------ .../UmbracoBuilder.DistributedCache.cs | 25 ++------- .../HostedServices/HealthCheckNotifier.cs | 6 +-- .../HostedServices/KeepAlive.cs | 6 +-- .../HostedServices/LogScrubber.cs | 6 +-- .../HostedServices/ScheduledPublishing.cs | 6 +-- .../ServerRegistration/TouchServerTask.cs | 4 +- .../InstallSteps/StarterKitDownloadStep.cs | 2 +- .../Enrichers/ThreadAbortExceptionEnricher.cs | 4 +- .../Logging/Serilog/SerilogComposer.cs | 21 -------- .../Implement/ServerRegistrationService.cs | 35 ++++++------- .../Sync/DatabaseServerMessenger.cs | 6 +-- .../Compose/ModelsBuilderComponent.cs | 2 +- .../UmbracoBuilderExtensions.cs} | 50 +++++++++--------- .../Implementations/TestHelper.cs | 2 +- src/Umbraco.Tests.Integration/RuntimeTests.cs | 6 ++- .../UmbracoBuilderExtensions.cs | 27 ---------- .../UmbracoTestServerTestBase.cs | 4 +- .../Testing/UmbracoIntegrationTest.cs | 16 +++--- .../DistributedCache/DistributedCacheTests.cs | 6 +-- .../HealthCheckNotifierTests.cs | 4 +- .../HostedServices/KeepAliveTests.cs | 4 +- .../HostedServices/LogScrubberTests.cs | 4 +- .../ScheduledPublishingTests.cs | 4 +- .../TouchServerTaskTests.cs | 5 +- .../Scoping/ScopedNuCacheTests.cs | 4 +- src/Umbraco.Tests/Scoping/ScopedXmlTests.cs | 2 +- .../Controllers/PackageInstallController.cs | 1 - .../AspNetCoreApplicationShutdownRegistry.cs | 17 +++---- .../AspNetCoreUmbracoApplicationLifetime.cs | 9 ++-- .../UmbracoBuilderExtensions.cs | 21 ++++---- .../Install/InstallApiController.cs | 2 +- .../Profiler/WebProfilerComponent.cs | 4 +- .../Runtime/AspNetCoreComponent.cs | 4 +- .../AspNetUmbracoApplicationLifetime.cs | 2 +- src/Umbraco.Web/UmbracoApplicationBase.cs | 4 +- 54 files changed, 273 insertions(+), 363 deletions(-) create mode 100644 src/Umbraco.Core/Diagnostics/NoopMarchal.cs rename src/Umbraco.Core/{Net => Hosting}/IUmbracoApplicationLifetime.cs (73%) create mode 100644 src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs create mode 100644 src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs create mode 100644 src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs rename src/Umbraco.Core/Logging/{VoidProfiler.cs => NoopProfiler.cs} (89%) delete mode 100644 src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs create mode 100644 src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs delete mode 100644 src/Umbraco.Core/Sync/IServerRegistrar.cs create mode 100644 src/Umbraco.Core/Sync/IServerRoleAccessor.cs delete mode 100644 src/Umbraco.Core/Sync/SingleServerRegistrar.cs create mode 100644 src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs delete mode 100644 src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs rename src/Umbraco.Tests.Integration/{Testing/IntegrationTestComposer.cs => DependencyInjection/UmbracoBuilderExtensions.cs} (78%) delete mode 100644 src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs index 3479bd74d6..5bd2fe9e8c 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Composing; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; +using Umbraco.Core.Composing; namespace Umbraco.Core.DependencyInjection { @@ -16,6 +15,8 @@ namespace Umbraco.Core.DependencyInjection /// public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) { + // TODO: Should have a better name + IEnumerable composerTypes = builder.TypeLoader.GetTypes(); IEnumerable enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 32eed6d78d..96f01d111a 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -8,10 +8,13 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Diagnostics; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; using Umbraco.Core.Hosting; @@ -107,6 +110,14 @@ namespace Umbraco.Core.DependencyInjection Services.AddLazySupport(); + // Adds no-op registrations as many core services require these dependencies but these + // dependencies cannot be fulfilled in the Core project + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + Services.AddUnique(); + + Services.AddUnique(); Services.AddUnique(); Services.AddUnique(factory => @@ -195,6 +206,16 @@ namespace Umbraco.Core.DependencyInjection Services.AddUnique(); Services.AddUnique(); + + // register a server registrar, by default it's the db registrar + Services.AddUnique(f => + { + GlobalSettings globalSettings = f.GetRequiredService>().Value; + var singleServer = globalSettings.DisableElectionForSingleServer; + return singleServer + ? (IServerRoleAccessor)new SingleServerRoleAccessor() + : new ElectedServerRoleAccessor(f.GetRequiredService()); + }); } } } diff --git a/src/Umbraco.Core/Diagnostics/NoopMarchal.cs b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs new file mode 100644 index 0000000000..09629f9595 --- /dev/null +++ b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Core.Diagnostics +{ + internal class NoopMarchal : IMarchal + { + public IntPtr GetExceptionPointers() => IntPtr.Zero; + } +} diff --git a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs similarity index 73% rename from src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs rename to src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs index a032720d46..a4368a2634 100644 --- a/src/Umbraco.Core/Net/IUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs @@ -1,25 +1,20 @@ using System; -namespace Umbraco.Net +namespace Umbraco.Core.Hosting { - // TODO: This shouldn't be in this namespace? public interface IUmbracoApplicationLifetime { /// /// A value indicating whether the application is restarting after the current request. /// bool IsRestarting { get; } + /// /// Terminates the current application. The application restarts the next time a request is received for it. /// void Restart(); + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications event EventHandler ApplicationInit; } - - - public interface IUmbracoApplicationLifetimeManager - { - void InvokeApplicationInit(); - } } diff --git a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs new file mode 100644 index 0000000000..778edc24dd --- /dev/null +++ b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Hosting +{ + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications + public interface IUmbracoApplicationLifetimeManager + { + void InvokeApplicationInit(); + } +} diff --git a/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs new file mode 100644 index 0000000000..3ffef04410 --- /dev/null +++ b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Hosting +{ + internal class NoopApplicationShutdownRegistry : IApplicationShutdownRegistry + { + public void RegisterObject(IRegisteredObject registeredObject) { } + public void UnregisterObject(IRegisteredObject registeredObject) { } + } +} diff --git a/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs new file mode 100644 index 0000000000..7833fd1224 --- /dev/null +++ b/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Hosting +{ + internal class NoopUmbracoApplicationLifetimeManager : IUmbracoApplicationLifetimeManager + { + public void InvokeApplicationInit() { } + } +} diff --git a/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs index e3cd56c5c1..4866c472e6 100644 --- a/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Core/Install/InstallSteps/StarterKitInstallStep.cs @@ -2,9 +2,9 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Umbraco.Core.Hosting; using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Net; using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps diff --git a/src/Umbraco.Core/Logging/VoidProfiler.cs b/src/Umbraco.Core/Logging/NoopProfiler.cs similarity index 89% rename from src/Umbraco.Core/Logging/VoidProfiler.cs rename to src/Umbraco.Core/Logging/NoopProfiler.cs index d771fd7630..e7b43e5e2d 100644 --- a/src/Umbraco.Core/Logging/VoidProfiler.cs +++ b/src/Umbraco.Core/Logging/NoopProfiler.cs @@ -1,8 +1,8 @@ -using System; +using System; namespace Umbraco.Core.Logging { - public class VoidProfiler : IProfiler + public class NoopProfiler : IProfiler { private readonly VoidDisposable _disposable = new VoidDisposable(); diff --git a/src/Umbraco.Core/Manifest/ManifestWatcher.cs b/src/Umbraco.Core/Manifest/ManifestWatcher.cs index e74393a179..b6cd82b31f 100644 --- a/src/Umbraco.Core/Manifest/ManifestWatcher.cs +++ b/src/Umbraco.Core/Manifest/ManifestWatcher.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Extensions.Logging; -using Umbraco.Net; +using Umbraco.Core.Hosting; namespace Umbraco.Core.Manifest { diff --git a/src/Umbraco.Core/Services/IServerRegistrationService.cs b/src/Umbraco.Core/Services/IServerRegistrationService.cs index 62bb68eb14..f0246dd287 100644 --- a/src/Umbraco.Core/Services/IServerRegistrationService.cs +++ b/src/Umbraco.Core/Services/IServerRegistrationService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Sync; @@ -11,9 +11,8 @@ namespace Umbraco.Core.Services /// Touches a server to mark it as active; deactivate stale servers. /// /// The server URL. - /// The server unique identity. /// The time after which a server is considered stale. - void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout); + void TouchServer(string serverAddress, TimeSpan staleTimeout); /// /// Deactivates a server. @@ -38,11 +37,6 @@ namespace Umbraco.Core.Services /// from the database. IEnumerable GetActiveServers(bool refresh = false); - /// - /// Gets the current server identity. - /// - string CurrentServerIdentity { get; } - /// /// Gets the role of the current server. /// diff --git a/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs b/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs deleted file mode 100644 index f361eb7a67..0000000000 --- a/src/Umbraco.Core/Sync/DatabaseServerRegistrar.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Sync -{ - /// - /// A registrar that stores registered server nodes in the database. - /// - /// - /// This is the default registrar which determines a server's role by using a master election process. - /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. - /// - public sealed class DatabaseServerRegistrar : IServerRegistrar - { - private readonly Lazy _registrationService; - - /// - /// Initializes a new instance of the class. - /// - /// The registration service. - /// Some options. - public DatabaseServerRegistrar(Lazy registrationService) - { - _registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService)); - } - - /// - /// Gets the registered servers. - /// - public IEnumerable Registrations => _registrationService.Value.GetActiveServers(); - - /// - /// Gets the role of the current server in the application environment. - /// - public ServerRole GetCurrentServerRole() - { - var service = _registrationService.Value; - return service.GetCurrentServerRole(); - } - - } -} diff --git a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs new file mode 100644 index 0000000000..e4accd046b --- /dev/null +++ b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs @@ -0,0 +1,29 @@ +using System; +using Umbraco.Core.Services; + +namespace Umbraco.Core.Sync +{ + /// + /// Gets the current server's based on active servers registered with + /// + /// + /// This is the default service which determines a server's role by using a master election process. + /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. + /// + public sealed class ElectedServerRoleAccessor : IServerRoleAccessor + { + private readonly IServerRegistrationService _registrationService; + + /// + /// Initializes a new instance of the class. + /// + /// The registration service. + /// Some options. + public ElectedServerRoleAccessor(IServerRegistrationService registrationService) => _registrationService = registrationService ?? throw new ArgumentNullException(nameof(registrationService)); + + /// + /// Gets the role of the current server in the application environment. + /// + public ServerRole CurrentServerRole => _registrationService.GetCurrentServerRole(); + } +} diff --git a/src/Umbraco.Core/Sync/IServerRegistrar.cs b/src/Umbraco.Core/Sync/IServerRegistrar.cs deleted file mode 100644 index 7e63b6b170..0000000000 --- a/src/Umbraco.Core/Sync/IServerRegistrar.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Sync -{ - /// - /// Provides server registrations to the distributed cache. - /// - public interface IServerRegistrar - { - /// - /// Gets the server registrations. - /// - IEnumerable Registrations { get; } // TODO: This isn't even used anymore, this whole interface can probably go away - - /// - /// Gets the role of the current server in the application environment. - /// - ServerRole GetCurrentServerRole(); - - } -} diff --git a/src/Umbraco.Core/Sync/IServerRoleAccessor.cs b/src/Umbraco.Core/Sync/IServerRoleAccessor.cs new file mode 100644 index 0000000000..b23acbac7c --- /dev/null +++ b/src/Umbraco.Core/Sync/IServerRoleAccessor.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Sync +{ + /// + /// Gets the current server's + /// + public interface IServerRoleAccessor + { + /// + /// Gets the role of the current server in the application environment. + /// + ServerRole CurrentServerRole { get; } + } +} diff --git a/src/Umbraco.Core/Sync/SingleServerRegistrar.cs b/src/Umbraco.Core/Sync/SingleServerRegistrar.cs deleted file mode 100644 index fe03e195b2..0000000000 --- a/src/Umbraco.Core/Sync/SingleServerRegistrar.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Web; - -namespace Umbraco.Core.Sync -{ - /// - /// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance - /// - /// - /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the - /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup - /// so this micro optimization doesn't really affect the primary startup phase. - /// - public class SingleServerRegistrar : IServerRegistrar - { - private readonly IRequestAccessor _requestAccessor; - private readonly Lazy _registrations; - - public IEnumerable Registrations => _registrations.Value; - - public SingleServerRegistrar(IRequestAccessor requestAccessor) - { - _requestAccessor = requestAccessor; - _registrations = new Lazy(() => new IServerAddress[] { new ServerAddressImpl(_requestAccessor.GetApplicationUrl().ToString()) }); - } - - public ServerRole GetCurrentServerRole() - { - return ServerRole.Single; - } - - - private class ServerAddressImpl : IServerAddress - { - public ServerAddressImpl(string serverAddress) - { - ServerAddress = serverAddress; - } - - public string ServerAddress { get; } - } - } -} diff --git a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs new file mode 100644 index 0000000000..65b9559522 --- /dev/null +++ b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using Umbraco.Web; + +namespace Umbraco.Core.Sync +{ + /// + /// Can be used when Umbraco is definitely not operating in a Load Balanced scenario to micro-optimize some startup performance + /// + /// + /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the + /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup + /// so this micro optimization doesn't really affect the primary startup phase. + /// + public class SingleServerRoleAccessor : IServerRoleAccessor + { + public ServerRole CurrentServerRole => ServerRole.Single; + } +} diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index caba831aff..6900354202 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web IScopeProvider scopeProvider, IProfilingLogger proflog, ILogger logger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index b5c76aad83..94c1e3dcfa 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -6,10 +6,10 @@ using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Dashboards; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; using Umbraco.Core.Install; +using Umbraco.Core.Logging.Serilog.Enrichers; using Umbraco.Core.Mail; using Umbraco.Core.Manifest; using Umbraco.Core.Media; @@ -19,28 +19,22 @@ using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Core.Templates; -using Umbraco.Core.Trees; using Umbraco.Examine; using Umbraco.Infrastructure.Examine; +using Umbraco.Infrastructure.Logging.Serilog.Enrichers; using Umbraco.Infrastructure.Media; using Umbraco.Infrastructure.Runtime; using Umbraco.Web; -using Umbraco.Web.Actions; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Editors; using Umbraco.Web.HealthCheck; using Umbraco.Web.HealthCheck.NotificationMethods; using Umbraco.Web.Install; using Umbraco.Web.Media; -using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Migrations.PostMigrations; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.PropertyEditors; @@ -48,39 +42,20 @@ using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Search; -using Umbraco.Web.Sections; using Umbraco.Web.Trees; namespace Umbraco.Infrastructure.DependencyInjection { public static partial class UmbracoBuilderExtensions { - - /* - * TODO: Many of these things are not "Core" services and are probably not required to run - * - * This should be split up: - * - Distributed Cache - * - BackOffice - * - Manifest - * - Property Editors - * - Packages - * - Dashboards - * - OEmbed - * - Sections - * - Content Apps - * - Health Checks - * - ETC... - * - Installation - * - Front End - */ - /// /// Adds all core Umbraco services required to run which may be replaced later in the pipeline /// public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder) { - builder.AddMainDom(); + builder + .AddMainDom() + .AddLogging(); builder.Services.AddUnique(); builder.Services.AddUnique(factory => factory.GetRequiredService().CreateDatabase()); @@ -155,7 +130,7 @@ namespace Umbraco.Infrastructure.DependencyInjection // register *all* checks, except those marked [HideFromTypeFinder] of course builder.Services.AddUnique(); - + builder.Services.AddUnique(); builder.Services.AddScoped(); @@ -198,10 +173,20 @@ namespace Umbraco.Infrastructure.DependencyInjection return builder; } + /// + /// Adds logging requirements for Umbraco + /// + private static IUmbracoBuilder AddLogging(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + return builder; + } + private static IUmbracoBuilder AddMainDom(this IUmbracoBuilder builder) { - builder.Services.AddUnique(); - builder.Services.AddUnique(factory => { var globalSettings = factory.GetRequiredService>().Value; diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index 8be46d38fb..3ad7556c92 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -26,27 +26,10 @@ namespace Umbraco.Infrastructure.DependencyInjection /// public static IUmbracoBuilder AddDistributedCache(this IUmbracoBuilder builder) { - // NOTE: the `DistributedCache` is registered in UmbracoBuilder since it's a core service - builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); builder.SetServerMessenger(); builder.AddNotificationHandler(); - // TODO: We don't need server registrar anymore - // register a server registrar, by default it's the db registrar - builder.Services.AddUnique(f => - { - var globalSettings = f.GetRequiredService>().Value; - - // TODO: we still register the full IServerMessenger because - // even on 1 single server we can have 2 concurrent app domains - var singleServer = globalSettings.DisableElectionForSingleServer; - return singleServer - ? (IServerRegistrar)new SingleServerRegistrar(f.GetRequiredService()) - : new DatabaseServerRegistrar( - new Lazy(f.GetRequiredService)); - }); - builder.Services.AddUnique(); return builder; } @@ -57,15 +40,15 @@ namespace Umbraco.Infrastructure.DependencyInjection /// The type of the server registrar. /// The builder. public static void SetServerRegistrar(this IUmbracoBuilder builder) - where T : class, IServerRegistrar - => builder.Services.AddUnique(); + where T : class, IServerRoleAccessor + => builder.Services.AddUnique(); /// /// Sets the server registrar. /// /// The builder. /// A function creating a server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) + public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) => builder.Services.AddUnique(factory); /// @@ -73,7 +56,7 @@ namespace Umbraco.Infrastructure.DependencyInjection /// /// The builder. /// A server registrar. - public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar) + public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor registrar) => builder.Services.AddUnique(registrar); /// diff --git a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs index cd89ebc046..c1412d4169 100644 --- a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs @@ -30,7 +30,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IRuntimeState _runtimeState; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IMainDom _mainDom; private readonly IScopeProvider _scopeProvider; private readonly ILogger _logger; @@ -54,7 +54,7 @@ namespace Umbraco.Infrastructure.HostedServices HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IRuntimeState runtimeState, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IMainDom mainDom, IScopeProvider scopeProvider, ILogger logger, @@ -87,7 +87,7 @@ namespace Umbraco.Infrastructure.HostedServices return; } - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs index 6a56b6f98e..0ec237c6d6 100644 --- a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs +++ b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs @@ -24,7 +24,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly KeepAliveSettings _keepAliveSettings; private readonly ILogger _logger; private readonly IProfilingLogger _profilingLogger; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IHttpClientFactory _httpClientFactory; /// @@ -43,7 +43,7 @@ namespace Umbraco.Infrastructure.HostedServices IOptions keepAliveSettings, ILogger logger, IProfilingLogger profilingLogger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IHttpClientFactory httpClientFactory) : base(TimeSpan.FromMinutes(5), DefaultDelay) { @@ -64,7 +64,7 @@ namespace Umbraco.Infrastructure.HostedServices } // Don't run on replicas nor unknown role servers - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs index ca87d3e84e..c933ee2470 100644 --- a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs @@ -23,7 +23,7 @@ namespace Umbraco.Infrastructure.HostedServices public class LogScrubber : RecurringHostedServiceBase { private readonly IMainDom _mainDom; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IAuditService _auditService; private readonly LoggingSettings _settings; private readonly IProfilingLogger _profilingLogger; @@ -42,7 +42,7 @@ namespace Umbraco.Infrastructure.HostedServices /// The profiling logger. public LogScrubber( IMainDom mainDom, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IAuditService auditService, IOptions settings, IScopeProvider scopeProvider, @@ -61,7 +61,7 @@ namespace Umbraco.Infrastructure.HostedServices internal override Task PerformExecuteAsync(object state) { - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs index bd73310c29..b42de1add5 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs @@ -27,7 +27,7 @@ namespace Umbraco.Infrastructure.HostedServices private readonly IRuntimeState _runtimeState; private readonly IServerMessenger _serverMessenger; private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IUmbracoContextFactory _umbracoContextFactory; /// @@ -44,7 +44,7 @@ namespace Umbraco.Infrastructure.HostedServices public ScheduledPublishing( IRuntimeState runtimeState, IMainDom mainDom, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger, @@ -69,7 +69,7 @@ namespace Umbraco.Infrastructure.HostedServices return Task.CompletedTask; } - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Replica: _logger.LogDebug("Does not run on replica servers."); diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs index 25e975582d..69f9280fc0 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs @@ -57,9 +57,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration try { - // TouchServer uses a proper unit of work etc underneath so even in a - // background task it is safe to call it without dealing with any scope. - _serverRegistrationService.TouchServer(serverAddress, _serverRegistrationService.CurrentServerIdentity, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout); + _serverRegistrationService.TouchServer(serverAddress, _globalSettings.DatabaseServerRegistrar.StaleServerTimeout); } catch (Exception ex) { diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs index 77385eb2fa..8bc5bcfdff 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs @@ -6,9 +6,9 @@ using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Security; -using Umbraco.Net; using Umbraco.Web.Install.Models; using Umbraco.Web.Security; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Install.InstallSteps { diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs index 8428b60fde..a85e52cffe 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Threading; using Microsoft.Extensions.Options; @@ -55,6 +55,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message)); } else + { try { var dumped = MiniDump.Dump(_marchal, _hostingEnvironment, withException: true); @@ -68,6 +69,7 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers message = "Failed to create a minidump. " + ex; logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadAbortExceptionInfo", message)); } + } } private static bool IsTimeoutThreadAbortException(Exception exception) diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs deleted file mode 100644 index 4d8046ee8c..0000000000 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging.Serilog.Enrichers; -using Umbraco.Infrastructure.Logging.Serilog.Enrichers; - -namespace Umbraco.Infrastructure.Logging.Serilog -{ - public class SerilogComposer : ICoreComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 145bf54aaf..14197762c6 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -1,8 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; -using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.Models; @@ -26,11 +25,12 @@ namespace Umbraco.Core.Services.Implement /// /// Initializes a new instance of the class. /// - /// A UnitOfWork provider. - /// A logger factory - /// - public ServerRegistrationService(IScopeProvider scopeProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, - IServerRegistrationRepository serverRegistrationRepository, IHostingEnvironment hostingEnvironment) + public ServerRegistrationService( + IScopeProvider scopeProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IServerRegistrationRepository serverRegistrationRepository, + IHostingEnvironment hostingEnvironment) : base(scopeProvider, loggerFactory, eventMessagesFactory) { _serverRegistrationRepository = serverRegistrationRepository; @@ -41,10 +41,10 @@ namespace Umbraco.Core.Services.Implement /// Touches a server to mark it as active; deactivate stale servers. /// /// The server URL. - /// The server unique identity. /// The time after which a server is considered stale. - public void TouchServer(string serverAddress, string serverIdentity, TimeSpan staleTimeout) + public void TouchServer(string serverAddress, TimeSpan staleTimeout) { + var serverIdentity = GetCurrentServerIdentity(); using (var scope = ScopeProvider.CreateScope()) { scope.WriteLock(Constants.Locks.Servers); @@ -144,19 +144,16 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Gets the local server identity. - /// - public string CurrentServerIdentity => NetworkHelper.MachineName // eg DOMAIN\SERVER - + "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT; - /// /// Gets the role of the current server. /// /// The role of the current server. - public ServerRole GetCurrentServerRole() - { - return _currentServerRole; - } + public ServerRole GetCurrentServerRole() => _currentServerRole; + + /// + /// Gets the local server identity. + /// + private string GetCurrentServerIdentity() => NetworkHelper.MachineName // eg DOMAIN\SERVER + + "/" + _hostingEnvironment.ApplicationId; // eg /LM/S3SVC/11/ROOT; } } diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 11e1596529..26b1de5080 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -40,7 +40,7 @@ namespace Umbraco.Core.Sync private readonly ManualResetEvent _syncIdle; private readonly object _locko = new object(); private readonly IProfilingLogger _profilingLogger; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IHostingEnvironment _hostingEnvironment; private readonly CacheRefresherCollection _cacheRefreshers; @@ -60,7 +60,7 @@ namespace Umbraco.Core.Sync IScopeProvider scopeProvider, IProfilingLogger proflog, ILogger logger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, @@ -312,7 +312,7 @@ namespace Umbraco.Core.Sync _lastPruned = _lastSync; - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Single: case ServerRole.Master: diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs index fb39007bd0..7afb166069 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs @@ -6,13 +6,13 @@ using Microsoft.Extensions.Options; using Umbraco.Configuration; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.ModelsBuilder.Embedded.BackOffice; -using Umbraco.Net; using Umbraco.Web.Common.Lifetime; using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.WebAssets; diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs similarity index 78% rename from src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs rename to src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs index 842a2a8a34..88e0e9f502 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,72 +1,70 @@ -using Moq; -using NUnit.Framework; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Runtime; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Sync; using Umbraco.Core.WebAssets; using Umbraco.Examine; +using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.Scheduling; using Umbraco.Web.Search; -using Umbraco.Infrastructure.Cache; -namespace Umbraco.Tests.Integration.Testing +namespace Umbraco.Tests.Integration.DependencyInjection { /// /// This is used to replace certain services that are normally registered from our Core / Infrastructure that /// we do not want active within integration tests /// - /// - /// This is a IUserComposer so that it runs after all core composers - /// - public class IntegrationTestComposer : ComponentComposer + public static class UmbracoBuilderExtensions { - // TODO: Kill this and only enable using ext methods what we need (first we need to kill composers) - - public override void Compose(IUmbracoBuilder builder) + /// + /// Uses/Replaces services with testing services + /// + public static IUmbracoBuilder AddTestServices(this IUmbracoBuilder builder, TestHelper testHelper) { - base.Compose(builder); + builder.Services.AddUnique(AppCaches.NoCache); + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(testHelper.MainDom); builder.Services.AddUnique(); - builder.Services.AddUnique(factory => Mock.Of()); + builder.Services.AddUnique(factory => Mock.Of()); // we don't want persisted nucache files in tests builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }); - #if IS_WINDOWS +#if IS_WINDOWS // ensure all lucene indexes are using RAM directory (no file system) builder.Services.AddUnique(); - #endif +#endif // replace this service so that it can lookup the correct file locations - builder.Services.AddUnique(GetLocalizedTextService); + builder.Services.AddUnique(GetLocalizedTextService); builder.Services.AddUnique(); builder.Services.AddUnique(); + + return builder; } /// /// Used to register a replacement for where the file sources are the ones within the netcore project so /// we don't need to copy files /// - private ILocalizedTextService GetLocalizedTextService(IServiceProvider factory) + private static ILocalizedTextService GetLocalizedTextService(IServiceProvider factory) { var globalSettings = factory.GetRequiredService>(); var loggerFactory = factory.GetRequiredService(); @@ -77,7 +75,7 @@ namespace Umbraco.Tests.Integration.Testing { // get the src folder var currFolder = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); - while(!currFolder.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase)) + while (!currFolder.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase)) { currFolder = currFolder.Parent; } @@ -98,8 +96,8 @@ namespace Umbraco.Tests.Integration.Testing // replace the default so there is no background index rebuilder private class TestBackgroundIndexRebuilder : BackgroundIndexRebuilder { - public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) - : base(mainDom, profilingLogger , loggerFactory, hostingEnvironment, indexRebuilder) + public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) + : base(mainDom, profilingLogger, loggerFactory, hostingEnvironment, indexRebuilder) { } diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs index fd9ffe5d26..9c2da39076 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -105,7 +105,7 @@ namespace Umbraco.Tests.Integration.Implementations public ILoggerFactory ConsoleLoggerFactory { get; private set; } public IProfilingLogger ProfilingLogger { get; private set; } - public IProfiler Profiler { get; } = new VoidProfiler(); + public IProfiler Profiler { get; } = new NoopProfiler(); public IHttpContextAccessor GetHttpContextAccessor() => _httpContextAccessor; diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index 394884a0db..502936a04a 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -37,10 +37,10 @@ namespace Umbraco.Tests.Integration } /// - /// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime + /// This will boot up umbraco with components enabled to show they initialize and shutdown /// [Test] - public async Task UseUmbracoCore() + public async Task Start_And_Stop_Umbraco_With_Components_Enabled() { var testHelper = new TestHelper(); @@ -70,6 +70,8 @@ namespace Umbraco.Tests.Integration builder.Services.AddUnique(AppCaches.NoCache); builder.AddConfiguration() .AddUmbracoCore() + .AddWebComponents() + .AddComposers() .Build(); services.AddRouting(); // LinkGenerator diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs deleted file mode 100644 index 796f9a8669..0000000000 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Moq; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Runtime; -using Umbraco.Tests.Integration.Implementations; -using Umbraco.Web.Common.DependencyInjection; - -namespace Umbraco.Tests.Integration.TestServerTest -{ - public static class UmbracoBuilderExtensions - { - /// - /// Uses a test version of Umbraco Core with a test IRuntime - /// - public static IUmbracoBuilder AddTestCore(this IUmbracoBuilder builder, TestHelper testHelper) - { - builder.AddUmbracoCore(); - - builder.Services.AddUnique(AppCaches.NoCache); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(testHelper.MainDom); - - return builder; - } - } -} diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 017b0ddb45..33c1c28e48 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Tests.Integration.DependencyInjection; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; @@ -135,7 +136,7 @@ namespace Umbraco.Tests.Integration.TestServerTest builder .AddConfiguration() - .AddTestCore(TestHelper) // This is the important one! + .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() .AddBackOfficeAuthentication() @@ -154,6 +155,7 @@ namespace Umbraco.Tests.Integration.TestServerTest mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly); }) .AddWebServer() + .AddTestServices(TestHelper) // This is the important one! .Build(); } diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index d8f27d27a7..21c3cf8304 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -27,8 +27,10 @@ using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.DependencyInjection; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.TestServerTest; using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.BackOffice.DependencyInjection; @@ -212,7 +214,6 @@ namespace Umbraco.Tests.Integration.Testing TestHelper.Profiler); var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); - builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); builder.AddConfiguration() @@ -222,13 +223,14 @@ namespace Umbraco.Tests.Integration.Testing builder.Services.AddUnique(Mock.Of()); builder.Services.AddUnique(TestHelper.MainDom); + //.AddTestServices(TestHelper) + builder.AddWebComponents() + .AddRuntimeMinifier() + .AddBackOfficeAuthentication() + .AddBackOfficeIdentity(); + //.AddComposers(); + services.AddSignalR(); - - builder.AddWebComponents(); - builder.AddRuntimeMinifier(); - builder.AddBackOfficeAuthentication(); - builder.AddBackOfficeIdentity(); - services.AddMvc(); builder.Build(); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs index 706ca94e71..0f16da11c7 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs @@ -18,7 +18,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache { private global::Umbraco.Web.Cache.DistributedCache _distributedCache; - private IServerRegistrar ServerRegistrar { get; set; } + private IServerRoleAccessor ServerRegistrar { get; set; } private TestServerMessenger ServerMessenger { get; set; } @@ -162,14 +162,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Cache.DistributedCache public void SendMessages() { } } - internal class TestServerRegistrar : IServerRegistrar + internal class TestServerRegistrar : IServerRoleAccessor { public IEnumerable Registrations => new List { new TestServerAddress("localhost") }; - public ServerRole GetCurrentServerRole() => throw new NotImplementedException(); + public ServerRole CurrentServerRole => throw new NotImplementedException(); } public class TestServerAddress : IServerAddress diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs index ffad002928..d5bd10fe3c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs @@ -138,8 +138,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRunTimeState = new Mock(); mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs index 98164a7aac..752da01f0f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs @@ -81,8 +81,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRequestAccessor = new Mock(); mockRequestAccessor.Setup(x => x.GetApplicationUrl()).Returns(new Uri(ApplicationUrl)); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs index 564b716f75..b7e2f7d80e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs @@ -67,8 +67,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices MaxLogAge = TimeSpan.FromMinutes(MaxLogAgeInMinutes), }; - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs index fa3a609ce6..17ff9f0c5d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs @@ -90,8 +90,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices var mockRunTimeState = new Mock(); mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.GetCurrentServerRole()).Returns(serverRole); + var mockServerRegistrar = new Mock(); + mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); var mockMainDom = new Mock(); mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs index 7f58f39346..d293a5b7e8 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs @@ -21,7 +21,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe private Mock _mockServerRegistrationService; private const string ApplicationUrl = "https://mysite.com/"; - private const string ServerIdentity = "Test/1"; private readonly TimeSpan _staleServerTimeout = TimeSpan.FromMinutes(2); [TestCase(RuntimeLevel.Boot)] @@ -63,8 +62,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe var mockLogger = new Mock>(); _mockServerRegistrationService = new Mock(); - _mockServerRegistrationService.SetupGet(x => x.CurrentServerIdentity).Returns(ServerIdentity); - + var settings = new GlobalSettings { DatabaseServerRegistrar = new DatabaseServerRegistrarSettings @@ -89,7 +87,6 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRe .Verify( x => x.TouchServer( It.Is(y => y == ApplicationUrl), - It.Is(y => y == ServerIdentity), It.Is(y => y == _staleServerTimeout)), times); } diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 4f424f4bb0..71809d063a 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; +using Umbraco.Core.Hosting; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; @@ -19,7 +20,6 @@ using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Infrastructure.PublishedCache.Persistence; -using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -47,7 +47,7 @@ namespace Umbraco.Tests.Scoping // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess Builder.Services.AddUnique(); - Builder.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); Builder.WithCollectionBuilder() .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index b4009d6f3e..af94f6b2e1 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.Scoping // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess Builder.Services.AddUnique(); - Builder.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); Builder.WithCollectionBuilder() .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs index 961ec388f7..d1f5d36b0f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs @@ -11,7 +11,6 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; -using Umbraco.Net; using Umbraco.Core.Packaging; using Umbraco.Core.Security; using Umbraco.Core.Services; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs index 57ad83d4ba..93347ddaa0 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs @@ -13,10 +13,11 @@ namespace Umbraco.Web.Common.AspNetCore private readonly ConcurrentDictionary _registeredObjects = new ConcurrentDictionary(); + /// + /// Initializes a new instance of the class. + /// public AspNetCoreApplicationShutdownRegistry(IHostApplicationLifetime hostApplicationLifetime) - { - _hostApplicationLifetime = hostApplicationLifetime; - } + => _hostApplicationLifetime = hostApplicationLifetime; public void RegisterObject(IRegisteredObject registeredObject) { @@ -43,17 +44,11 @@ namespace Umbraco.Web.Common.AspNetCore { private readonly IRegisteredObject _inner; - public RegisteredObjectWrapper(IRegisteredObject inner) - { - _inner = inner; - } + public RegisteredObjectWrapper(IRegisteredObject inner) => _inner = inner; public CancellationTokenRegistration CancellationTokenRegistration { get; set; } - public void Stop(bool immediate) - { - _inner.Stop(immediate); - } + public void Stop(bool immediate) => _inner.Stop(immediate); } } } diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs index f34197d23e..cdba8273a0 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUmbracoApplicationLifetime.cs @@ -1,22 +1,21 @@ using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; -using Umbraco.Net; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Common.AspNetCore { public class AspNetCoreUmbracoApplicationLifetime : IUmbracoApplicationLifetime, IUmbracoApplicationLifetimeManager { - private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostApplicationLifetime _hostApplicationLifetime; - public AspNetCoreUmbracoApplicationLifetime(IHttpContextAccessor httpContextAccessor, IHostApplicationLifetime hostApplicationLifetime) + public AspNetCoreUmbracoApplicationLifetime(IHostApplicationLifetime hostApplicationLifetime) { - _httpContextAccessor = httpContextAccessor; _hostApplicationLifetime = hostApplicationLifetime; } public bool IsRestarting { get; set; } + public void Restart() { IsRestarting = true; @@ -27,6 +26,8 @@ namespace Umbraco.Web.Common.AspNetCore { ApplicationInit?.Invoke(this, EventArgs.Empty); } + + // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications public event EventHandler ApplicationInit; } } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 29e3820637..a2dde620b9 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -88,8 +88,6 @@ namespace Umbraco.Web.Common.DependencyInjection throw new ArgumentNullException(nameof(config)); } - // TODO: Should some/all of these registrations be moved directly into UmbracoBuilder? - IHostingEnvironment tempHostingEnvironment = GetTemporaryHostingEnvironment(webHostEnvironment, config); var loggingDir = tempHostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.LogFiles); @@ -116,6 +114,9 @@ namespace Umbraco.Web.Common.DependencyInjection /// /// Adds core Umbraco services /// + /// + /// This will not add any composers/components + /// public static IUmbracoBuilder AddUmbracoCore(this IUmbracoBuilder builder) { if (builder is null) @@ -142,8 +143,9 @@ namespace Umbraco.Web.Common.DependencyInjection builder.AddCoreInitialServices(); - // TODO: This should be a separate call to opt-in to plugins - builder.AddComposers(); + // aspnet app lifetime mgmt + builder.Services.AddMultipleUnique(); + builder.Services.AddUnique(); return builder; } @@ -232,11 +234,6 @@ namespace Umbraco.Web.Common.DependencyInjection builder.Services.AddUnique(); builder.Services.AddUnique(); - // Our own netcore implementations - builder.Services.AddMultipleUnique(); - - builder.Services.AddUnique(); - // The umbraco request lifetime builder.Services.AddMultipleUnique(); @@ -278,9 +275,11 @@ namespace Umbraco.Web.Common.DependencyInjection builder.Services.AddUnique(); builder.Services.AddUnique(); - builder.AddNuCache(); builder.AddHttpClients(); + // TODO: Does this belong in web components?? + builder.AddNuCache(); + return builder; } @@ -364,7 +363,7 @@ namespace Umbraco.Web.Common.DependencyInjection { // should let it be null, that's how MiniProfiler is meant to work, // but our own IProfiler expects an instance so let's get one - return new VoidProfiler(); + return new NoopProfiler(); } var webProfiler = new WebProfiler(); diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs index 8c32796ad8..6deecc2ce5 100644 --- a/src/Umbraco.Web.Common/Install/InstallApiController.cs +++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs @@ -7,9 +7,9 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; -using Umbraco.Net; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs index 0c10b7d95a..498b550c1a 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Logging; -using Umbraco.Net; using Umbraco.Web.Common.Lifetime; using Umbraco.Web.Common.Middleware; +using Umbraco.Core.Hosting; namespace Umbraco.Web.Common.Profiler { @@ -31,7 +31,7 @@ namespace Umbraco.Web.Common.Profiler if (_profiler != null) return; // if VoidProfiler was registered, let it be known - if (profiler is VoidProfiler) + if (profiler is NoopProfiler) logger.LogInformation( "Profiler is VoidProfiler, not profiling (must run debug mode to profile)."); _profile = false; diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs index 9309bd7e38..5c7e47cf3f 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComponent.cs @@ -1,9 +1,9 @@ -using System; +using System; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Net; +using Umbraco.Core.Hosting; using Umbraco.Web.Common.Lifetime; namespace Umbraco.Web.Common.Runtime diff --git a/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs b/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs index f0ff6e3cad..90261b1a5a 100644 --- a/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs +++ b/src/Umbraco.Web/AspNet/AspNetUmbracoApplicationLifetime.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Web; -using Umbraco.Net; +using Umbraco.Core.Hosting; namespace Umbraco.Web.AspNet { diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index bdf5b40a02..82182e26b7 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -68,10 +68,10 @@ namespace Umbraco.Web { // should let it be null, that's how MiniProfiler is meant to work, // but our own IProfiler expects an instance so let's get one - return new VoidProfiler(); + return new NoopProfiler(); } - return new VoidProfiler(); + return new NoopProfiler(); } protected UmbracoApplicationBase(ILogger logger, ILoggerFactory loggerFactory, SecuritySettings securitySettings, GlobalSettings globalSettings, ConnectionStrings connectionStrings, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) From cc84c866bcb2aac3187ef7a241c0edc9e44808d4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 16:44:50 +1100 Subject: [PATCH 06/16] moves file --- .../UmbracoBuilder.DistributedCache.cs | 2 +- .../{ => Sync}/BatchedDatabaseServerMessenger.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) rename src/Umbraco.Infrastructure/{ => Sync}/BatchedDatabaseServerMessenger.cs (96%) diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index 3ad7556c92..54c0feeea0 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; using Umbraco.Infrastructure.Cache; -using Umbraco.Web; +using Umbraco.Core.Sync; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; using Umbraco.Web.Search; diff --git a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs similarity index 96% rename from src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs rename to src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs index 6900354202..c265461c99 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs @@ -12,8 +12,9 @@ using Umbraco.Core.Logging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; using Umbraco.Core.Sync; +using Umbraco.Web; -namespace Umbraco.Web +namespace Umbraco.Core.Sync { /// /// An implementation that works by storing messages in the database. @@ -61,7 +62,8 @@ namespace Umbraco.Web public override void SendMessages() { var batch = GetBatch(false); - if (batch == null) return; + if (batch == null) + return; var instructions = batch.SelectMany(x => x.Instructions).ToArray(); batch.Clear(); @@ -95,7 +97,8 @@ namespace Umbraco.Web { var key = nameof(BatchedDatabaseServerMessenger); - if (!_requestCache.IsAvailable) return null; + if (!_requestCache.IsAvailable) + return null; // no thread-safety here because it'll run in only 1 thread (request) at a time var batch = (ICollection)_requestCache.Get(key); From 1a0d961e42cf6831cb215b8f577c44fbbc738327 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 24 Dec 2020 18:11:16 +1100 Subject: [PATCH 07/16] removes WebsiteComposer, BackOfficeComposer --- src/Umbraco.Core/Composing/Composers.cs | 3 +- .../ComponentRuntimeTests.cs | 76 ++++++++++ .../UmbracoBuilderExtensions.cs | 4 +- src/Umbraco.Tests.Integration/RuntimeTests.cs | 132 ------------------ .../UmbracoTestServerTestBase.cs | 1 + .../Testing/UmbracoIntegrationTest.cs | 17 +-- .../UmbracoBuilderExtensions.cs | 54 ++++++- .../Runtime/BackOfficeComposer.cs | 64 --------- .../Runtime/AspNetCoreComposer.cs | 27 ---- src/Umbraco.Web.UI.NetCore/Startup.cs | 1 + .../UmbracoBuilderExtensions.cs | 7 + .../Runtime/WebsiteComposer.cs | 24 ---- 12 files changed, 147 insertions(+), 263 deletions(-) create mode 100644 src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs delete mode 100644 src/Umbraco.Tests.Integration/RuntimeTests.cs delete mode 100644 src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs delete mode 100644 src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs diff --git a/src/Umbraco.Core/Composing/Composers.cs b/src/Umbraco.Core/Composing/Composers.cs index 47f272cbf4..91c8244324 100644 --- a/src/Umbraco.Core/Composing/Composers.cs +++ b/src/Umbraco.Core/Composing/Composers.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -70,7 +70,6 @@ namespace Umbraco.Core.Composing foreach (var composer in composers) { - var componentType = composer.GetType(); composer.Compose(_builder); } } diff --git a/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs b/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs new file mode 100644 index 0000000000..ba6c6473fa --- /dev/null +++ b/src/Umbraco.Tests.Integration/ComponentRuntimeTests.cs @@ -0,0 +1,76 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.DependencyInjection; +using Umbraco.Extensions; +using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Tests.Integration.Extensions; +using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; +using Umbraco.Web.Common.DependencyInjection; + +namespace Umbraco.Tests.Integration +{ + + [TestFixture] + [UmbracoTest(Boot = true)] + public class ComponentRuntimeTests : UmbracoIntegrationTest + { + // ensure composers are added + protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddComposers(); + + /// + /// This will boot up umbraco with components enabled to show they initialize and shutdown + /// + [Test] + public async Task Start_And_Stop_Umbraco_With_Components_Enabled() + { + IRuntime runtime = Services.GetRequiredService(); + IRuntimeState runtimeState = Services.GetRequiredService(); + IMainDom mainDom = Services.GetRequiredService(); + ComponentCollection components = Services.GetRequiredService(); + + MyComponent myComponent = components.OfType().First(); + + Assert.IsTrue(mainDom.IsMainDom); + Assert.IsNull(runtimeState.BootFailedException); + Assert.IsTrue(myComponent.IsInit, "The component was not initialized"); + + // force stop now + await runtime.StopAsync(CancellationToken.None); + Assert.IsTrue(myComponent.IsTerminated, "The component was not terminated"); + } + + public class MyComposer : IUserComposer + { + public void Compose(IUmbracoBuilder builder) => builder.Components().Append(); + } + + public class MyComponent : IComponent + { + public bool IsInit { get; private set; } + + public bool IsTerminated { get; private set; } + + private readonly ILogger _logger; + + public MyComponent(ILogger logger) => _logger = logger; + + public void Initialize() => IsInit = true; + + public void Terminate() => IsTerminated = true; + + } + } +} diff --git a/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs index 88e0e9f502..c1bdf19069 100644 --- a/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs @@ -34,9 +34,9 @@ namespace Umbraco.Tests.Integration.DependencyInjection /// /// Uses/Replaces services with testing services /// - public static IUmbracoBuilder AddTestServices(this IUmbracoBuilder builder, TestHelper testHelper) + public static IUmbracoBuilder AddTestServices(this IUmbracoBuilder builder, TestHelper testHelper, AppCaches appCaches = null) { - builder.Services.AddUnique(AppCaches.NoCache); + builder.Services.AddUnique(appCaches ?? AppCaches.NoCache); builder.Services.AddUnique(Mock.Of()); builder.Services.AddUnique(testHelper.MainDom); diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs deleted file mode 100644 index 502936a04a..0000000000 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.DependencyInjection; -using Umbraco.Extensions; -using Umbraco.Infrastructure.PublishedCache.DependencyInjection; -using Umbraco.Tests.Integration.Extensions; -using Umbraco.Tests.Integration.Implementations; -using Umbraco.Web.Common.DependencyInjection; - -namespace Umbraco.Tests.Integration -{ - - [TestFixture] - public class RuntimeTests - { - [TearDown] - public void TearDown() - { - MyComponent.Reset(); - MyComposer.Reset(); - } - - [SetUp] - public void Setup() - { - MyComponent.Reset(); - MyComposer.Reset(); - } - - /// - /// This will boot up umbraco with components enabled to show they initialize and shutdown - /// - [Test] - public async Task Start_And_Stop_Umbraco_With_Components_Enabled() - { - var testHelper = new TestHelper(); - - IHostBuilder hostBuilder = new HostBuilder() - .ConfigureServices((hostContext, services) => - { - IWebHostEnvironment webHostEnvironment = testHelper.GetWebHostEnvironment(); - services.AddSingleton(testHelper.DbProviderFactoryCreator); - services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); - - // Add it! - TypeLoader typeLoader = services.AddTypeLoader( - GetType().Assembly, - webHostEnvironment, - testHelper.GetHostingEnvironment(), - testHelper.ConsoleLoggerFactory, - AppCaches.NoCache, - hostContext.Configuration, - testHelper.Profiler); - - var builder = new UmbracoBuilder( - services, - hostContext.Configuration, - typeLoader, - testHelper.ConsoleLoggerFactory); - - builder.Services.AddUnique(AppCaches.NoCache); - builder.AddConfiguration() - .AddUmbracoCore() - .AddWebComponents() - .AddComposers() - .Build(); - - services.AddRouting(); // LinkGenerator - }); - - IHost host = await hostBuilder.StartAsync(); - var app = new ApplicationBuilder(host.Services); - - app.UseUmbracoCore(); - - // assert results - IRuntimeState runtimeState = app.ApplicationServices.GetRequiredService(); - IMainDom mainDom = app.ApplicationServices.GetRequiredService(); - - Assert.IsTrue(mainDom.IsMainDom); - Assert.IsNull(runtimeState.BootFailedException); - Assert.IsTrue(MyComponent.IsInit); - - await host.StopAsync(); - - Assert.IsTrue(MyComponent.IsTerminated); - } - - public class MyComposer : IUserComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Components().Append(); - IsComposed = true; - } - - public static void Reset() => IsComposed = false; - - public static bool IsComposed { get; private set; } - } - - public class MyComponent : IComponent - { - public static bool IsInit { get; private set; } - - public static bool IsTerminated { get; private set; } - - private readonly ILogger _logger; - - public MyComponent(ILogger logger) => _logger = logger; - - public void Initialize() => IsInit = true; - - public void Terminate() => IsTerminated = true; - - public static void Reset() - { - IsTerminated = false; - IsInit = false; - } - } - } -} diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 33c1c28e48..27209182fe 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -139,6 +139,7 @@ namespace Umbraco.Tests.Integration.TestServerTest .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() + .AddBackOfficeCore() .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies(TestAuthHandler.TestAuthenticationScheme) diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 21c3cf8304..17778f986c 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -217,25 +217,20 @@ namespace Umbraco.Tests.Integration.Testing builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); builder.AddConfiguration() - .AddUmbracoCore(); - - builder.Services.AddUnique(GetAppCaches()); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(TestHelper.MainDom); - - //.AddTestServices(TestHelper) - builder.AddWebComponents() + .AddUmbracoCore() + .AddWebComponents() .AddRuntimeMinifier() .AddBackOfficeAuthentication() - .AddBackOfficeIdentity(); + .AddBackOfficeIdentity() + .AddTestServices(TestHelper, GetAppCaches()); //.AddComposers(); services.AddSignalR(); services.AddMvc(); - builder.Build(); - CustomTestSetup(builder); + + builder.Build(); } protected virtual AppCaches GetAppCaches() diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index 30e6bdcbc7..fb2cbfb607 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,11 +1,21 @@ using System; +using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Services; +using Umbraco.Extensions; using Umbraco.Infrastructure.DependencyInjection; -using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Web.BackOffice.Authorization; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Filters; +using Umbraco.Web.BackOffice.Middleware; +using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.BackOffice.Services; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Authorization; using Umbraco.Web.Common.DependencyInjection; @@ -25,6 +35,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() + .AddBackOfficeCore() .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies() @@ -64,6 +75,11 @@ namespace Umbraco.Web.BackOffice.DependencyInjection }); builder.Services.ConfigureOptions(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + return builder; } @@ -117,5 +133,41 @@ namespace Umbraco.Web.BackOffice.DependencyInjection /// public static TreeCollectionBuilder Trees(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); + + public static IUmbracoBuilder AddBackOfficeCore(this IUmbracoBuilder builder) + { + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // register back office trees + // the collection builder only accepts types inheriting from TreeControllerBase + // and will filter out those that are not attributed with TreeAttribute + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.Trees() + .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); + + builder.ComposeWebMappingProfiles(); + + builder.Services.AddUnique(factory => + { + var path = "~/"; + var hostingEnvironment = factory.GetRequiredService(); + return new PhysicalFileSystem( + factory.GetRequiredService(), + hostingEnvironment, + factory.GetRequiredService>(), + hostingEnvironment.MapPathContentRoot(path), + hostingEnvironment.ToAbsolute(path) + ); + }); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + return builder; + } } } diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs deleted file mode 100644 index d933d00d68..0000000000 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Composing; -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Services; -using Umbraco.Extensions; -using Umbraco.Web.BackOffice.Controllers; -using Umbraco.Web.BackOffice.DependencyInjection; -using Umbraco.Web.BackOffice.Filters; -using Umbraco.Web.BackOffice.Middleware; -using Umbraco.Web.BackOffice.Routing; -using Umbraco.Web.BackOffice.Security; -using Umbraco.Web.BackOffice.Services; -using Umbraco.Web.BackOffice.Trees; -using Umbraco.Web.Common.Runtime; - -namespace Umbraco.Web.BackOffice.Runtime -{ - [ComposeBefore(typeof(ICoreComposer))] - [ComposeAfter(typeof(AspNetCoreComposer))] - public class BackOfficeComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - // register back office trees - // the collection builder only accepts types inheriting from TreeControllerBase - // and will filter out those that are not attributed with TreeAttribute - var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); - builder.Trees() - .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); - - builder.ComposeWebMappingProfiles(); - - builder.Services.AddUnique(factory => - { - var path = "~/"; - var hostingEnvironment = factory.GetRequiredService(); - return new PhysicalFileSystem( - factory.GetRequiredService(), - hostingEnvironment, - factory.GetRequiredService>(), - hostingEnvironment.MapPathContentRoot(path), - hostingEnvironment.ToAbsolute(path) - ); - }); - - builder.Services.AddUnique(); - builder.Services.AddUnique(); - } - } -} diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 34a8b7583a..1eda1cc23a 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -1,31 +1,4 @@ -using System.Linq; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.DependencyInjection; using Umbraco.Core.Composing; -using Umbraco.Core.Diagnostics; -using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; -using Umbraco.Core.Security; -using Umbraco.Extensions; -using Umbraco.Net; -using Umbraco.Web.Common.AspNetCore; -using Umbraco.Web.Common.Controllers; -using Umbraco.Web.Common.Install; -using Umbraco.Web.Common.Lifetime; -using Umbraco.Web.Common.Macros; -using Umbraco.Web.Common.Middleware; -using Umbraco.Web.Common.Profiler; -using Umbraco.Web.Common.Routing; -using Umbraco.Web.Common.Security; -using Umbraco.Web.Common.Templates; -using Umbraco.Web.Macros; -using Umbraco.Web.Security; -using Umbraco.Web.Templates; -using Umbraco.Web.Common.ModelBinders; -using Umbraco.Infrastructure.DependencyInjection; - namespace Umbraco.Web.Common.Runtime { diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 75212e3077..a09b850d98 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -46,6 +46,7 @@ namespace Umbraco.Web.UI.NetCore services.AddUmbraco(_env, _config) .AddBackOffice() .AddWebsite() + .AddComposers() .Build(); #pragma warning restore IDE0022 // Use expression body for methods diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 5762a5fb69..52f6d5df11 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -2,8 +2,10 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core.DependencyInjection; +using Umbraco.Extensions; using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Web.Website.Collections; using Umbraco.Web.Website.Controllers; using Umbraco.Web.Website.Routing; using Umbraco.Web.Website.ViewEngines; @@ -20,6 +22,11 @@ namespace Umbraco.Web.Website.DependencyInjection /// public static IUmbracoBuilder AddWebsite(this IUmbracoBuilder builder) { + builder.Services.AddUnique(); + + builder.WithCollectionBuilder() + .Add(builder.TypeLoader.GetSurfaceControllers()); + // Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection // to inject dependencies into the viewEngines) builder.Services.AddTransient, RenderMvcViewOptionsSetup>(); diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs deleted file mode 100644 index 2a4b85a0df..0000000000 --- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Extensions; -using Umbraco.Web.Website.Routing; -using Umbraco.Web.Common.Runtime; -using Umbraco.Web.Website.Collections; - -namespace Umbraco.Web.Website.Runtime -{ - // web's initial composer composes after core's, and before all core composers - [ComposeBefore(typeof(ICoreComposer))] - [ComposeAfter(typeof(AspNetCoreComposer))] - public class WebsiteComposer : IComposer - { - public void Compose(IUmbracoBuilder builder) - { - builder.Services.AddUnique(); - - builder.WithCollectionBuilder() - .Add(builder.TypeLoader.GetSurfaceControllers()); - } - } -} - From 4ce5dc8eff552d5c67c48f09259f7644335f67b9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 11:32:36 +1100 Subject: [PATCH 08/16] fixing tests --- .../DependencyInjection/UmbracoBuilder.Events.cs | 5 +++-- .../TestServerTest/UmbracoTestServerTestBase.cs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs index d5090de01b..138fa9bf9c 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs @@ -24,8 +24,9 @@ namespace Umbraco.Core.DependencyInjection where TNotification : INotification { // Register the handler as transient. This ensures that anything can be injected into it. - // TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 - builder.Services.TryAddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); + // TODO: Waiting on feedback here for TryAddTransient https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 + // ... though this will fail tests so it's not the final answer so we'll see where that discussion goes. + builder.Services.AddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); return builder; } } diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index 27209182fe..5a704c2b5d 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -25,6 +25,7 @@ using Umbraco.Web.BackOffice.DependencyInjection; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.DependencyInjection; using Umbraco.Web.Website.Controllers; +using Umbraco.Web.Website.DependencyInjection; namespace Umbraco.Tests.Integration.TestServerTest { @@ -156,6 +157,7 @@ namespace Umbraco.Tests.Integration.TestServerTest mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly); }) .AddWebServer() + .AddWebsite() .AddTestServices(TestHelper) // This is the important one! .Build(); } From 2848f4083b2e672256bbb15ccd44042125e4d76e Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 12:01:52 +1100 Subject: [PATCH 09/16] notes - why isn't this building? --- .../DependencyInjection/UmbracoBuilder.Configuration.cs | 7 ------- .../Extensions/ApplicationBuilderExtensions.cs | 3 +++ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs index 1733536908..a31a44beeb 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index 5c7c4ee713..5dee7d10e1 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -28,6 +28,9 @@ namespace Umbraco.Extensions /// public static IApplicationBuilder UseUmbraco(this IApplicationBuilder app) { + // TODO: Should we do some checks like this to verify that the corresponding "Add" methods have been called for the + // corresponding "Use" methods? + // https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Mvc/Mvc.Core/src/Builder/MvcApplicationBuilderExtensions.cs#L132 if (app == null) { throw new ArgumentNullException(nameof(app)); From 999c20a75576be4df86f0b51d109c30648884b94 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 12:22:03 +1100 Subject: [PATCH 10/16] Fixes UmbracoIntegrationTest Mapping flag and missing using in Startup --- .../Testing/UmbracoIntegrationTest.cs | 10 +++++++++- .../Umbraco.Core/Mapping/UmbracoMapperTests.cs | 2 +- .../DependencyInjection/UmbracoBuilderExtensions.cs | 2 +- .../Extensions/WebMappingProfiles.cs | 2 +- src/Umbraco.Web.UI.NetCore/Startup.cs | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 17778f986c..885668acca 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -25,6 +25,7 @@ using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; using Umbraco.Core.Strings; using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Infrastructure.PublishedCache.DependencyInjection; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.DependencyInjection; @@ -223,7 +224,14 @@ namespace Umbraco.Tests.Integration.Testing .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddTestServices(TestHelper, GetAppCaches()); - //.AddComposers(); + + if (TestOptions.Mapper) + { + // TODO: Should these just be called from within AddUmbracoCore/AddWebComponents? + builder + .AddCoreMappingProfiles() + .AddWebMappingProfiles(); + } services.AddSignalR(); services.AddMvc(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs index 4028889b01..244e8c8d1a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Linq; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index fb2cbfb607..0d12fae687 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -149,7 +149,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection builder.Trees() .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); - builder.ComposeWebMappingProfiles(); + builder.AddWebMappingProfiles(); builder.Services.AddUnique(factory => { diff --git a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs index eeb0903e88..f66c175f29 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs @@ -7,7 +7,7 @@ namespace Umbraco.Extensions { public static class WebMappingProfiles { - public static IUmbracoBuilder ComposeWebMappingProfiles(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddWebMappingProfiles(this IUmbracoBuilder builder) { builder.WithCollectionBuilder() .Add() diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index a09b850d98..46f7b2d7ae 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; using Umbraco.Web.BackOffice.DependencyInjection; using Umbraco.Web.BackOffice.Security; From cf9dd9bfeca897ec2dc93c552cb4f5c7e4a4bec0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 12:48:59 +1100 Subject: [PATCH 11/16] Adds notes, another hacky fix for hacky test/code --- .../Cache/DatabaseServerMessengerNotificationHandler.cs | 5 ++++- .../DependencyInjection/UmbracoBuilder.DistributedCache.cs | 5 ----- .../Umbraco.Infrastructure/Services/ContentServiceTests.cs | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs index c8d8c81ab1..5b4dd4f0ed 100644 --- a/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -70,7 +70,10 @@ namespace Umbraco.Infrastructure.Cache } // TODO: I don't really know or think that the Application Url plays a role anymore with the DB dist cache, - // this might be really old stuff + // this might be really old stuff. I 'think' all this is doing is ensuring that the IRequestAccessor.GetApplicationUrl + // is definitely called during the first request. If that is still required, that logic doesn't belong here. That logic + // should be part of it's own service/middleware. There's also TODO notes within IRequestAccessor.GetApplicationUrl directly + // mentioning that the property doesn't belong on that service either. This should be investigated and resolved in a separate task. private void EnsureApplicationUrlOnce(object sender, RoutableAttemptEventArgs e) { if (e.Outcome == EnsureRoutableOutcome.IsRoutable || e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs index 54c0feeea0..db1d22e86c 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -1,15 +1,10 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Events; -using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; using Umbraco.Infrastructure.Cache; -using Umbraco.Core.Sync; using Umbraco.Web.Cache; using Umbraco.Web.PublishedCache; using Umbraco.Web.Search; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs index c9f8dc5391..10fe206290 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -2283,7 +2283,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // This sleep ensures the save is called on later ticks then the SetValue and SetCultureName. Therefore // we showcase the currect lack of handling dirty on variants on save. When this is implemented the sleep // helps showcase the functionality is actually working - Thread.Sleep(1); + Thread.Sleep(5); ContentService.Save(page); var versionId5 = page.VersionId; From d1d664c44952f2cdd3e2b820f86ed982ccba07c9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 12:51:13 +1100 Subject: [PATCH 12/16] removes unneeded cast --- .../HostedServices/ServerRegistration/InstructionProcessTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs index f3d970d2b0..8b194e32ef 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs @@ -31,7 +31,7 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration : base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1)) { _runtimeState = runtimeState; - _messenger = messenger as IServerMessenger ?? throw new ArgumentNullException(nameof(messenger)); + _messenger = messenger; _logger = logger; } From cbc08fb00879315b6191c9da0688695425c8180d Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 12:56:44 +1100 Subject: [PATCH 13/16] notes/cleanup --- .../Sync/BatchedDatabaseServerMessenger.cs | 40 ++++++++++--------- .../Sync/DatabaseServerMessenger.cs | 5 +-- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs index c265461c99..d1a9481f47 100644 --- a/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs @@ -4,14 +4,12 @@ using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; -using Umbraco.Core.Sync; using Umbraco.Web; namespace Umbraco.Core.Sync @@ -19,9 +17,6 @@ namespace Umbraco.Core.Sync /// /// An implementation that works by storing messages in the database. /// - /// - /// This binds to appropriate umbraco events in order to trigger the Boot(), Sync() & FlushBatch() calls - /// public class BatchedDatabaseServerMessenger : DatabaseServerMessenger { private readonly IRequestCache _requestCache; @@ -48,37 +43,41 @@ namespace Umbraco.Core.Sync _requestAccessor = requestAccessor; } + /// protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) { var idsA = ids?.ToArray(); - Type arrayType; - if (GetArrayType(idsA, out arrayType) == false) + if (GetArrayType(idsA, out Type arrayType) == false) + { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); + } BatchMessage(refresher, messageType, idsA, arrayType, json); } + /// public override void SendMessages() { - var batch = GetBatch(false); + ICollection batch = GetBatch(false); if (batch == null) + { return; + } - var instructions = batch.SelectMany(x => x.Instructions).ToArray(); + RefreshInstruction[] instructions = batch.SelectMany(x => x.Instructions).ToArray(); batch.Clear(); // Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount - using (var scope = ScopeProvider.CreateScope()) + using (IScope scope = ScopeProvider.CreateScope()) { - foreach (var instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) + foreach (IEnumerable instructionsBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) { WriteInstructions(scope, instructionsBatch); } scope.Complete(); } - } private void WriteInstructions(IScope scope, IEnumerable instructions) @@ -93,12 +92,14 @@ namespace Umbraco.Core.Sync scope.Database.Insert(dto); } - protected ICollection GetBatch(bool create) + private ICollection GetBatch(bool create) { var key = nameof(BatchedDatabaseServerMessenger); if (!_requestCache.IsAvailable) + { return null; + } // no thread-safety here because it'll run in only 1 thread (request) at a time var batch = (ICollection)_requestCache.Get(key); @@ -111,26 +112,27 @@ namespace Umbraco.Core.Sync return batch; } - protected void BatchMessage( + private void BatchMessage( ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, Type idType = null, string json = null) { - var batch = GetBatch(true); - var instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json); + ICollection batch = GetBatch(true); + IEnumerable instructions = RefreshInstruction.GetInstructions(refresher, messageType, ids, idType, json); // batch if we can, else write to DB immediately if (batch == null) { - //only write the json blob with a maximum count of the MaxProcessingInstructionCount - using (var scope = ScopeProvider.CreateScope()) + // only write the json blob with a maximum count of the MaxProcessingInstructionCount + using (IScope scope = ScopeProvider.CreateScope()) { - foreach (var maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) + foreach (IEnumerable maxBatch in instructions.InGroupsOf(GlobalSettings.DatabaseServerMessenger.MaxProcessingInstructionCount)) { WriteInstructions(scope, maxBatch); } + scope.Complete(); } } diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 26b1de5080..09c90461ac 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -25,9 +25,6 @@ namespace Umbraco.Core.Sync /// public abstract class DatabaseServerMessenger : ServerMessengerBase { - // TODO: This class is never used directly, only BatchedDatabaseServerMessenger is used so - // this could/should be combined with that or made abstract and/or just cleaned up. - // TODO: This class needs to be split into a service/repo for DB access /* @@ -55,7 +52,7 @@ namespace Umbraco.Core.Sync /// /// Initializes a new instance of the class. /// - public DatabaseServerMessenger( + protected DatabaseServerMessenger( IMainDom mainDom, IScopeProvider scopeProvider, IProfilingLogger proflog, From d46545faa01a3a8f0a7dad086de6888ccdaf0e8e Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 13:01:49 +1100 Subject: [PATCH 14/16] For now, we explicitly require AddDistributedCache in Startup so it's not called twice. --- .../DependencyInjection/UmbracoBuilderExtensions.cs | 3 +-- src/Umbraco.Web.UI.NetCore/Startup.cs | 2 ++ .../DependencyInjection/UmbracoBuilderExtensions.cs | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index 0d12fae687..6bb75e774a 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -43,8 +43,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddMvcAndRazor() .AddWebServer() .AddPreviewSupport() - .AddHostedServices() - .AddDistributedCache(); + .AddHostedServices(); /// /// Adds Umbraco back office authentication requirements diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 46f7b2d7ae..5b262098e6 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; +using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Web.BackOffice.DependencyInjection; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.DependencyInjection; @@ -47,6 +48,7 @@ namespace Umbraco.Web.UI.NetCore services.AddUmbraco(_env, _config) .AddBackOffice() .AddWebsite() + .AddDistributedCache() .AddComposers() .Build(); #pragma warning restore IDE0022 // Use expression body for methods diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 52f6d5df11..41292b9415 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -43,8 +43,6 @@ namespace Umbraco.Web.Website.DependencyInjection builder.Services.AddScoped(); builder.Services.AddSingleton(); - builder.AddDistributedCache(); - return builder; } From 34427b010434e73c56a9cb5fb21060f1f6e8cc24 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 13:22:29 +1100 Subject: [PATCH 15/16] Moves AddDistributed cache back to being called implicitly, ensures notification handlers are not added twice --- .../DependencyInjection/UmbracoBuilder.Events.cs | 12 +++++++++--- .../Umbraco.Core/Events/EventAggregatorTests.cs | 1 + .../DependencyInjection/UmbracoBuilderExtensions.cs | 3 ++- src/Umbraco.Web.UI.NetCore/Startup.cs | 2 -- .../DependencyInjection/UmbracoBuilderExtensions.cs | 2 ++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs index 138fa9bf9c..c24936b4fb 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Events.cs @@ -24,9 +24,15 @@ namespace Umbraco.Core.DependencyInjection where TNotification : INotification { // Register the handler as transient. This ensures that anything can be injected into it. - // TODO: Waiting on feedback here for TryAddTransient https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 - // ... though this will fail tests so it's not the final answer so we'll see where that discussion goes. - builder.Services.AddTransient(typeof(INotificationHandler), typeof(TNotificationHandler)); + var descriptor = new ServiceDescriptor(typeof(INotificationHandler), typeof(TNotificationHandler), ServiceLifetime.Transient); + + // TODO: Waiting on feedback here https://github.com/umbraco/Umbraco-CMS/pull/9556/files#r548365396 about whether + // we perform this duplicate check or not. + if (!builder.Services.Contains(descriptor)) + { + builder.Services.Add(descriptor); + } + return builder; } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs index 08d78af59e..cbf3d02542 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Events/EventAggregatorTests.cs @@ -13,6 +13,7 @@ using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Events { + [TestFixture] public class EventAggregatorTests { private const int A = 3; diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index 6bb75e774a..0d12fae687 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -43,7 +43,8 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddMvcAndRazor() .AddWebServer() .AddPreviewSupport() - .AddHostedServices(); + .AddHostedServices() + .AddDistributedCache(); /// /// Adds Umbraco back office authentication requirements diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 5b262098e6..46f7b2d7ae 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; -using Umbraco.Infrastructure.DependencyInjection; using Umbraco.Web.BackOffice.DependencyInjection; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.DependencyInjection; @@ -48,7 +47,6 @@ namespace Umbraco.Web.UI.NetCore services.AddUmbraco(_env, _config) .AddBackOffice() .AddWebsite() - .AddDistributedCache() .AddComposers() .Build(); #pragma warning restore IDE0022 // Use expression body for methods diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 41292b9415..52f6d5df11 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -43,6 +43,8 @@ namespace Umbraco.Web.Website.DependencyInjection builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.AddDistributedCache(); + return builder; } From a6f281789b53722a958acaff409521d0ab244bd5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 4 Jan 2021 13:29:13 +1100 Subject: [PATCH 16/16] Add explicit package sources --- NuGet.Config | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/NuGet.Config b/NuGet.Config index d6c63173f8..92eaf83792 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,13 +1,15 @@  - - - - - - + + + + + + +