diff --git a/NuGet.Config b/NuGet.Config index d6c63173f8..92eaf83792 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,13 +1,15 @@  - - - - - - + + + + + + + diff --git a/src/Umbraco.Core/Cache/DistributedCache.cs b/src/Umbraco.Core/Cache/DistributedCache.cs index 698e97c610..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); @@ -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/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/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.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/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs deleted file mode 100644 index 58aac7b811..0000000000 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Umbraco.Core.DependencyInjection; -using Umbraco.Core.Composing; -using Umbraco.Core.HealthCheck; -using Umbraco.Core.Manifest; -using Umbraco.Core.PropertyEditors; -using Umbraco.Web.Actions; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Dashboards; -using Umbraco.Web.Editors; -using Umbraco.Web.Routing; -using Umbraco.Web.Sections; -using Umbraco.Web.Tour; - -namespace Umbraco.Core -{ - public static partial class CompositionExtensions - { - - #region Collection Builders - - /// - /// Gets the actions collection builder. - /// - /// The builder. - /// - public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the content apps collection builder. - /// - /// The builder. - /// - public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the content finders collection builder. - /// - /// The builder. - /// - public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the editor validators collection builder. - /// - /// The builder. - /// - public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the health checks collection builder. - /// - /// The builder. - public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the TourFilters collection builder. - /// - public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the URL providers collection builder. - /// - /// The builder. - public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the media url providers collection builder. - /// - /// The builder. - public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the backoffice sections/applications collection builder. - /// - /// The builder. - public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - /// - /// Gets the components collection builder. - /// - public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder(); - - - /// - /// Gets the backoffice dashboards collection builder. - /// - /// The builder. - public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) - => builder.WithCollectionBuilder() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .Add() - .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/ServiceCollectionExtensions.cs b/src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs similarity index 89% rename from src/Umbraco.Core/ServiceCollectionExtensions.cs rename to src/Umbraco.Core/DependencyInjection/ServiceCollectionExtensions.cs index d1c89ea17e..97e70da9be 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,9 +49,9 @@ 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) + internal static IServiceCollection AddLazySupport(this IServiceCollection services) { services.Replace(ServiceDescriptor.Transient(typeof(Lazy<>), typeof(LazyResolve<>))); return 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/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs new file mode 100644 index 0000000000..f6dc6fd6ff --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -0,0 +1,275 @@ +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; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + 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. + /// + /// The builder. + public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the content apps collection builder. + /// + /// The builder. + public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the content finders collection builder. + /// + /// The builder. + public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the editor validators collection builder. + /// + /// The builder. + public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the health checks collection builder. + /// + /// The builder. + public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + public static HealthCheckNotificationMethodCollectionBuilder HealthCheckNotificationMethods(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the TourFilters collection builder. + /// + public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the URL providers collection builder. + /// + /// The builder. + public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the media url providers collection builder. + /// + /// The builder. + public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice sections/applications collection builder. + /// + /// The builder. + public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the components collection builder. + /// + public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + + /// + /// Gets the backoffice dashboards collection builder. + /// + /// The builder. + public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) + => 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. + /// + /// 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..5bd2fe9e8c --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Composers.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; + +namespace Umbraco.Core.DependencyInjection +{ + /// + /// Extension methods for + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Adds Umbraco composers for plugins + /// + 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(); + + 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..a31a44beeb --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +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..c24936b4fb 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,15 @@ 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)); + 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.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index d56712cdcf..96f01d111a 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -3,28 +3,65 @@ 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 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; +using Umbraco.Core.IO; +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; +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 { 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 +80,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 +94,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(); } @@ -66,6 +107,115 @@ namespace Umbraco.Core.DependencyInjection // Register as singleton to allow injection everywhere. Services.AddSingleton(p => p.GetService); Services.AddSingleton(); + + 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 => + { + 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.AddAllCoreCollectionBuilders(); + 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(); + + 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/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/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/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/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/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/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.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/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.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.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.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/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/IBatchedDatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/IBatchedDatabaseServerMessenger.cs deleted file mode 100644 index 560b7fb235..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 : IDatabaseServerMessenger - { - 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..df2d665057 100644 --- a/src/Umbraco.Core/Sync/IServerMessenger.cs +++ b/src/Umbraco.Core/Sync/IServerMessenger.cs @@ -1,21 +1,30 @@ -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(); + + /// + /// 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 . @@ -24,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 . @@ -33,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 . @@ -42,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.Core/Sync/IServerRegistrar.cs b/src/Umbraco.Core/Sync/IServerRegistrar.cs deleted file mode 100644 index 780f865ad7..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; } - - /// - /// 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.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.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/Cache/DatabaseServerMessengerNotificationHandler.cs b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs new file mode 100644 index 0000000000..5b4dd4f0ed --- /dev/null +++ b/src/Umbraco.Infrastructure/Cache/DatabaseServerMessengerNotificationHandler.cs @@ -0,0 +1,96 @@ +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 IServerMessenger _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; + } + + /// + 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 += 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. 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) + { + _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 EndRequest(object sender, UmbracoRequestEventArgs e) => _messenger?.SendMessages(); + } +} 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/Installer.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs deleted file mode 100644 index 31b3133e4d..0000000000 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -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/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..4da9c93fb3 --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs @@ -0,0 +1,25 @@ +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.Core.Trees; +using Umbraco.Web.Media.EmbedProviders; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + /// + /// Provides extension methods to the class. + /// + public static partial class UmbracoBuilderExtensions + { + /// + /// Gets the mappers collection builder. + /// + /// The builder. + public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs new file mode 100644 index 0000000000..94c1e3dcfa --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -0,0 +1,208 @@ +using System.Runtime.InteropServices; +using Examine; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +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; +using Umbraco.Core.Migrations; +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.ValueConverters; +using Umbraco.Core.Runtime; +using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; +using Umbraco.Core.Templates; +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.HealthCheck; +using Umbraco.Web.HealthCheck.NotificationMethods; +using Umbraco.Web.Install; +using Umbraco.Web.Media; +using Umbraco.Web.Migrations.PostMigrations; +using Umbraco.Web.Models.PublishedContent; +using Umbraco.Web.PropertyEditors; +using Umbraco.Web.PropertyEditors.ValueConverters; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.Routing; +using Umbraco.Web.Search; +using Umbraco.Web.Trees; + +namespace Umbraco.Infrastructure.DependencyInjection +{ + public static partial class UmbracoBuilderExtensions + { + /// + /// 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() + .AddLogging(); + + 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 + .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 + // has been frozen and it is too late + builder.Mappers().AddCoreMappers(); + + // register the scope provider + builder.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor + builder.Services.AddUnique(f => f.GetRequiredService()); + builder.Services.AddUnique(f => f.GetRequiredService()); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // register database builder + // *not* a singleton, don't want to keep it around + builder.Services.AddTransient(); + + // register manifest parser, will be injected in collection builders where needed + builder.Services.AddUnique(); + + // register the manifest filter collection builder (collection is empty by default) + builder.ManifestFilters(); + + builder.MediaUrlGenerators() + .Add() + .Add(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(factory + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); + + builder.Services.AddUnique(factory => new MigrationBuilder(factory)); + + builder.Services.AddUnique(); + + // register the published snapshot accessor - the "current" published snapshot is in the umbraco context + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + // Config manipulator + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + // both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be + // 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(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + // register *all* checks, except those marked [HideFromTypeFinder] of course + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddScoped(); + + // replace + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddScoped(); + + builder.Services.AddUnique(); + builder.Services.AddScoped(factory => + { + var umbCtx = factory.GetRequiredService(); + return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); + }); + + // register accessors for cultures + builder.Services.AddUnique(); + + builder.Services.AddSingleton(); + + builder.Services.AddUnique(); + + // Register noop versions for examine to be overridden by examine + builder.Services.AddUnique(); + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.Services.AddUnique(); + + builder.AddInstaller(); + + 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(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 new file mode 100644 index 0000000000..db1d22e86c --- /dev/null +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.DistributedCache.cs @@ -0,0 +1,131 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.DependencyInjection; +using Umbraco.Core.Events; +using Umbraco.Core.Services.Changes; +using Umbraco.Core.Sync; +using Umbraco.Infrastructure.Cache; +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) + { + builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); + builder.SetServerMessenger(); + builder.AddNotificationHandler(); + + 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, 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) + => builder.Services.AddUnique(factory); + + /// + /// Sets the server registrar. + /// + /// The builder. + /// A server registrar. + public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRoleAccessor 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/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs similarity index 88% rename from src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs rename to src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs index f098cfaf57..5c61fd2c60 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs @@ -1,16 +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; -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 @@ -34,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..e5bdd844d8 --- /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 + /// + internal 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/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/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/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 4c235255c2..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."); @@ -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/HostedServices/ServerRegistration/InstructionProcessTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs index 3c291f187b..8b194e32ef 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; _logger = logger; } 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 fc26f922eb..0000000000 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs +++ /dev/null @@ -1,22 +0,0 @@ -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; -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/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/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/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/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/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/Runtime/CoreInitialServices.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialServices.cs deleted file mode 100644 index 32f5e6bf36..0000000000 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialServices.cs +++ /dev/null @@ -1,392 +0,0 @@ -using System; -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.Logging; -using Umbraco.Core.Manifest; -using Umbraco.Core.Media; -using Umbraco.Core.Migrations; -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.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; -using Umbraco.Infrastructure.Media; -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; -using Umbraco.Web.Media; -using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Migrations.PostMigrations; -using Umbraco.Web.Models.PublishedContent; -using Umbraco.Web.PropertyEditors; -using Umbraco.Web.PropertyEditors.ValueConverters; -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; - -namespace Umbraco.Infrastructure.Runtime -{ - public static class CoreInitialServices - { - public static IUmbracoBuilder AddCoreInitialServices(this IUmbracoBuilder builder) - { - builder.AddNotificationHandler(); - - builder.Services.AddSingleton(); - builder.AddNotificationHandler(); - - // composers - builder - .ComposeRepositories() - .ComposeServices() - .ComposeCoreMappingProfiles() - .ComposeFileSystems(); - - // 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 - // has been frozen and it is too late - builder.Mappers().AddCoreMappers(); - - // register the scope provider - builder.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor - builder.Services.AddUnique(f => f.GetRequiredService()); - builder.Services.AddUnique(f => f.GetRequiredService()); - - 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 - builder.Services.AddTransient(); - - // 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(); - - // 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()); - - 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)); - - // by default, register a noop factory - builder.Services.AddUnique(); - - // by default - 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(); - - // 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 - builder.PropertyValueConverters() - .Remove() - .Remove() - .Remove(); - - builder.UrlProviders() - .Append() - .Append(); - - builder.MediaUrlProviders() - .Append(); - - builder.Services.AddUnique(); - - // register properties fallback - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - builder.Actions() - .Add(() => builder.TypeLoader.GetTypes()); - - 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 - // 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 published router - builder.Services.AddUnique(); - - // 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 some services - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - builder.Services.AddUnique(); - 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 => - { - var umbCtx = factory.GetRequiredService(); - 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(); - - builder.Services.AddSingleton(); - - builder.Services.AddUnique(); - - // Register noop versions for examine to be overridden by examine - builder.Services.AddUnique(); - builder.Services.AddUnique(); - - builder.Services.AddUnique(); - - 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; - } - } -} 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/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.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.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/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs similarity index 58% rename from src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs rename to src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs index 187eced6e4..d1a9481f47 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs @@ -1,104 +1,83 @@ -using System; +using System; using System.Collections.Generic; 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; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; -using Umbraco.Core.Sync; -using Umbraco.Web.Routing; +using Umbraco.Web; -namespace Umbraco.Web +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, IBatchedDatabaseServerMessenger + public class BatchedDatabaseServerMessenger : DatabaseServerMessenger { - private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IRequestCache _requestCache; private readonly IRequestAccessor _requestAccessor; + /// + /// Initializes a new instance of the class. + /// public BatchedDatabaseServerMessenger( IMainDom mainDom, - IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, IProfilingLogger proflog, ILogger logger, - IServerRegistrar serverRegistrar, + IServerRoleAccessor serverRegistrar, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, 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(); - 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 void FlushBatch() + /// + public override void SendMessages() { - var batch = GetBatch(false); - if (batch == null) return; + 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()) + // Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount + 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) @@ -113,11 +92,14 @@ namespace Umbraco.Web scope.Database.Insert(dto); } - protected ICollection GetBatch(bool create) + private ICollection GetBatch(bool create) { 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); @@ -130,26 +112,27 @@ namespace Umbraco.Web 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 856772148f..09c90461ac 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -23,19 +23,21 @@ 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 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; - private readonly IServerRegistrar _serverRegistrar; + private readonly IServerRoleAccessor _serverRegistrar; private readonly IHostingEnvironment _hostingEnvironment; private readonly CacheRefresherCollection _cacheRefreshers; @@ -43,22 +45,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; } - - public DatabaseServerMessenger( - IMainDom mainDom, IScopeProvider scopeProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, IProfilingLogger proflog, ILogger logger, IServerRegistrar serverRegistrar, - bool distributedEnabled, DatabaseServerMessengerCallbacks callbacks, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IOptions globalSettings) + /// + /// Initializes a new instance of the class. + /// + protected DatabaseServerMessenger( + IMainDom mainDom, + IScopeProvider scopeProvider, + IProfilingLogger proflog, + ILogger logger, + IServerRoleAccessor 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 +84,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 +116,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 +144,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 +163,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 +172,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 +192,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 +216,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 +239,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 +300,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(); @@ -277,7 +309,7 @@ namespace Umbraco.Core.Sync _lastPruned = _lastSync; - switch (_serverRegistrar.GetCurrentServerRole()) + switch (_serverRegistrar.CurrentServerRole) { case ServerRole.Single: case ServerRole.Master: @@ -292,7 +324,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 +338,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 +353,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 +366,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 +406,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 +454,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 +538,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..dfba90291b 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; @@ -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)); @@ -365,5 +365,8 @@ namespace Umbraco.Core.Sync //} #endregion + + public abstract void Sync(); + public abstract void SendMessages(); } } 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/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.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/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/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs similarity index 64% rename from src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs rename to src/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs index 39d74f8869..c1bdf19069 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.Compose; using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.Scheduling; using Umbraco.Web.Search; -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 { - public override void Compose(IUmbracoBuilder builder) + /// + /// Uses/Replaces services with testing services + /// + public static IUmbracoBuilder AddTestServices(this IUmbracoBuilder builder, TestHelper testHelper, AppCaches appCaches = null) { - base.Compose(builder); + builder.Services.AddUnique(appCaches ?? AppCaches.NoCache); + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(testHelper.MainDom); - builder.Components().Remove(); 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) { } @@ -114,45 +112,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/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 deleted file mode 100644 index 258f1992ff..0000000000 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -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(); - } - - /// - /// Calling AddUmbracoCore to configure the container and UseUmbracoCore to start the runtime - /// - [Test] - public async Task UseUmbracoCore() - { - var testHelper = new TestHelper(); - - var hostBuilder = new HostBuilder() - .ConfigureServices((hostContext, services) => - { - var webHostEnvironment = testHelper.GetWebHostEnvironment(); - services.AddSingleton(testHelper.DbProviderFactoryCreator); - services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); - - // Add it! - - var 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() - .AddNuCache() - .Build(); - - services.AddRouting(); // LinkGenerator - }); - - var host = await hostBuilder.StartAsync(); - var app = new ApplicationBuilder(host.Services); - - app.UseUmbracoCore(); - - - // assert results - var runtimeState = app.ApplicationServices.GetRequiredService(); - var 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/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 ef3735032e..5a704c2b5d 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; @@ -24,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 { @@ -135,9 +137,10 @@ namespace Umbraco.Tests.Integration.TestServerTest builder .AddConfiguration() - .AddTestCore(TestHelper) // This is the important one! + .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() + .AddBackOfficeCore() .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies(TestAuthHandler.TestAuthenticationScheme) @@ -154,7 +157,8 @@ namespace Umbraco.Tests.Integration.TestServerTest mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly); }) .AddWebServer() - .AddNuCache() + .AddWebsite() + .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..885668acca 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -25,10 +25,13 @@ 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; 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,28 +215,30 @@ 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() - .AddUmbracoCore(); + .AddUmbracoCore() + .AddWebComponents() + .AddRuntimeMinifier() + .AddBackOfficeAuthentication() + .AddBackOfficeIdentity() + .AddTestServices(TestHelper, GetAppCaches()); - builder.Services.AddUnique(GetAppCaches()); - builder.Services.AddUnique(Mock.Of()); - builder.Services.AddUnique(TestHelper.MainDom); + if (TestOptions.Mapper) + { + // TODO: Should these just be called from within AddUmbracoCore/AddWebComponents? + builder + .AddCoreMappingProfiles() + .AddWebMappingProfiles(); + } services.AddSignalR(); - - builder.AddWebComponents(); - builder.AddRuntimeMinifier(); - builder.AddBackOfficeAuthentication(); - builder.AddBackOfficeIdentity(); - services.AddMvc(); - builder.Build(); - CustomTestSetup(builder); + + builder.Build(); } protected virtual AppCaches GetAppCaches() 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.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.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index 11f4095f53..0a1e46274b 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() { @@ -335,6 +328,10 @@ 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) { 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..68ec7fcf5f 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() { @@ -2171,6 +2166,10 @@ 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.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; 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.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..b23ccc9080 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -18,10 +18,12 @@ 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; 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.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Cache/DistributedCache/DistributedCacheTests.cs index 1023e47dfa..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; } @@ -127,45 +127,49 @@ 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) + 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 + 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.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.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/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.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/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/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.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..71809d063a 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -8,7 +8,9 @@ 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.Hosting; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; @@ -18,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; @@ -46,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 6814210cc4..af94f6b2e1 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; @@ -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; @@ -39,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()); } @@ -299,6 +300,10 @@ 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) { 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..8c89905c97 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -38,6 +38,8 @@ using Umbraco.Tests.Common.Builders; 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/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..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; @@ -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; @@ -382,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) @@ -451,7 +452,7 @@ namespace Umbraco.Tests.Testing if (withApplication == false) return; // default Datalayer/Repositories/SQL/Database/etc... - Builder.ComposeRepositories(); + Builder.AddRepositories(); Builder.Services.AddUnique(); @@ -496,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.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/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/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/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.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/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs index e8c6171f01..0d12fae687 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,10 +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.Infrastructure.PublishedCache.DependencyInjection; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Services; +using Umbraco.Extensions; +using Umbraco.Infrastructure.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; @@ -24,6 +35,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() + .AddBackOfficeCore() .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies() @@ -32,8 +44,7 @@ namespace Umbraco.Web.BackOffice.DependencyInjection .AddWebServer() .AddPreviewSupport() .AddHostedServices() - .AddHttpClients() - .AddNuCache(); + .AddDistributedCache(); /// /// Adds Umbraco back office authentication requirements @@ -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.AddWebMappingProfiles(); + + 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/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.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs deleted file mode 100644 index e9bf69f2c0..0000000000 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ /dev/null @@ -1,65 +0,0 @@ -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; -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.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/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.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/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 39a3eb3dce..a2dde620b9 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,20 +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 @@ -50,6 +70,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, @@ -91,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) @@ -98,12 +124,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(), @@ -111,107 +141,11 @@ 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(); - 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)); + // aspnet app lifetime mgmt + builder.Services.AddMultipleUnique(); + builder.Services.AddUnique(); return builder; } @@ -232,8 +166,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; @@ -278,6 +211,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 @@ -294,6 +230,56 @@ namespace Umbraco.Web.Common.DependencyInjection builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); builder.Services.AddUmbracoImageSharp(builder.Config); + // AspNetCore specific services + builder.Services.AddUnique(); + 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.AddHttpClients(); + + // TODO: Does this belong in web components?? + builder.AddNuCache(); + return builder; } @@ -377,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/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)); 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/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/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 deleted file mode 100644 index a23f880e7e..0000000000 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Core; -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/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.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 49dcf5a6db..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.Composing.CompositionExtensions; -using Umbraco.Web.Macros; -using Umbraco.Web.Security; -using Umbraco.Web.Templates; -using Umbraco.Web.Common.ModelBinders; - namespace Umbraco.Web.Common.Runtime { @@ -35,63 +8,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.ComposeInstaller(); - - 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.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.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 75212e3077..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; @@ -46,6 +47,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 f495c09d3c..52f6d5df11 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -2,7 +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; @@ -19,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>(); @@ -35,7 +43,7 @@ namespace Umbraco.Web.Website.DependencyInjection builder.Services.AddScoped(); builder.Services.AddSingleton(); - builder.AddNuCache(); + builder.AddDistributedCache(); return builder; } diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs deleted file mode 100644 index a40b29aea2..0000000000 --- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Umbraco.Core; -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()); - } - } -} - 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) 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;