diff --git a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs b/src/Umbraco.PublishedCache.NuCache/Extensions/NuCacheUmbracoBuilderExtensions.cs similarity index 61% rename from src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs rename to src/Umbraco.PublishedCache.NuCache/Extensions/NuCacheUmbracoBuilderExtensions.cs index c1c80cf43c..ee0b0e2630 100644 --- a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs +++ b/src/Umbraco.PublishedCache.NuCache/Extensions/NuCacheUmbracoBuilderExtensions.cs @@ -1,35 +1,39 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Models; using Umbraco.Core.Scoping; using Umbraco.Core.Services; -using Umbraco.Infrastructure.PublishedCache; using Umbraco.Infrastructure.PublishedCache.Persistence; +using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.NuCache; -namespace Umbraco.Web.PublishedCache.NuCache +namespace Umbraco.Infrastructure.PublishedCache.Extensions { - // TODO: We'll need to change this stuff to IUmbracoBuilder ext and control the order of things there, - // see comment in ModelsBuilderComposer which requires this weird IPublishedCacheComposer - public class NuCacheComposer : IComposer, IPublishedCacheComposer + /// + /// Extension methods for for the Umbraco's NuCache + /// + public static class NuCacheUmbracoBuilderExtensions { - /// - public void Compose(IUmbracoBuilder builder) + /// + /// Adds Umbraco NuCache dependencies + /// + public static IUmbracoBuilder AddNuCache(this IUmbracoBuilder builder) { // register the NuCache database data source - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); // register the NuCache published snapshot service // must register default options, required in the service ctor - builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions()); + builder.Services.TryAddTransient(factory => new PublishedSnapshotServiceOptions()); builder.SetPublishedSnapshotService(); // Add as itself - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); // replace this service since we want to improve the content/media // mapping lookups if we are using nucache. @@ -49,6 +53,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // add the NuCache health check (hidden from type finder) // TODO: no NuCache health check yet // composition.HealthChecks().Add(); + return builder; } } } diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index f74a95af4c..a5239bf05e 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.DependencyInjection; using Umbraco.Extensions; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; +using Umbraco.Web.Common.Extensions; namespace Umbraco.Tests.Integration { diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs index 0fcf47978a..cfab1e29c5 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -4,6 +4,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.DependencyInjection; using Umbraco.Core.Runtime; using Umbraco.Tests.Integration.Implementations; +using Umbraco.Web.Common.Extensions; namespace Umbraco.Tests.Integration.TestServerTest { diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index cc3df709af..d2b7f1664d 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -20,6 +20,7 @@ using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Common.Extensions; using Umbraco.Web.Website.Controllers; namespace Umbraco.Tests.Integration.TestServerTest @@ -135,7 +136,7 @@ namespace Umbraco.Tests.Integration.TestServerTest .AddTestCore(TestHelper) // This is the important one! .AddWebComponents() .AddRuntimeMinifier() - .AddBackOffice() + .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies(TestAuthHandler.TestAuthenticationScheme) .AddPreviewSupport() diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 414ad6ec43..823071ad11 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -30,6 +30,7 @@ using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Testing; using Umbraco.Web; +using Umbraco.Web.Common.Extensions; namespace Umbraco.Tests.Integration.Testing { @@ -223,7 +224,7 @@ namespace Umbraco.Tests.Integration.Testing builder.AddWebComponents(); builder.AddRuntimeMinifier(); - builder.AddBackOffice(); + builder.AddBackOfficeAuthentication(); builder.AddBackOfficeIdentity(); services.AddMvc(); diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeUmbracoBuilderExtensions.cs similarity index 70% rename from src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs rename to src/Umbraco.Web.BackOffice/Extensions/BackOfficeUmbracoBuilderExtensions.cs index 336855dd1b..16afd976db 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeUmbracoBuilderExtensions.cs @@ -1,22 +1,26 @@ using System; -using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.DependencyInjection; -using Umbraco.Web.BackOffice.Filters; +using Umbraco.Infrastructure.PublishedCache.Extensions; using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.Common.Extensions; namespace Umbraco.Extensions { - public static class UmbracoBuilderExtensions + /// + /// Extension methods for for the Umbraco back office + /// + public static class BackOfficeUmbracoBuilderExtensions { - public static IUmbracoBuilder AddAllBackOfficeComponents(this IUmbracoBuilder builder) - { - return builder + /// + /// Adds all required components to run the Umbraco back office + /// + public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder) => builder .AddConfiguration() .AddUmbracoCore() .AddWebComponents() .AddRuntimeMinifier() - .AddBackOffice() + .AddBackOfficeAuthentication() .AddBackOfficeIdentity() .AddBackOfficeAuthorizationPolicies() .AddMiniProfiler() @@ -24,22 +28,29 @@ namespace Umbraco.Extensions .AddWebServer() .AddPreviewSupport() .AddHostedServices() - .AddHttpClients(); - } + .AddHttpClients() + .AddNuCache(); - public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder) + /// + /// Adds Umbraco back office authentication requirements + /// + public static IUmbracoBuilder AddBackOfficeAuthentication(this IUmbracoBuilder builder) { builder.Services.AddAntiforgery(); builder.Services - .AddAuthentication() // This just creates a builder, nothing more - // Add our custom schemes which are cookie handlers + + // This just creates a builder, nothing more + .AddAuthentication() + + // Add our custom schemes which are cookie handlers .AddCookie(Core.Constants.Security.BackOfficeAuthenticationType) .AddCookie(Core.Constants.Security.BackOfficeExternalAuthenticationType, o => { o.Cookie.Name = Core.Constants.Security.BackOfficeExternalAuthenticationType; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }) + // Although we don't natively support this, we add it anyways so that if end-users implement the required logic // they don't have to worry about manually adding this scheme or modifying the sign in manager .AddCookie(Core.Constants.Security.BackOfficeTwoFactorAuthenticationType, o => @@ -52,6 +63,9 @@ namespace Umbraco.Extensions return builder; } + /// + /// Adds Identity support for Umbraco back office + /// public static IUmbracoBuilder AddBackOfficeIdentity(this IUmbracoBuilder builder) { builder.Services.AddUmbracoBackOfficeIdentity(); @@ -59,9 +73,13 @@ namespace Umbraco.Extensions return builder; } + /// + /// Adds Umbraco back office authorization policies + /// public static IUmbracoBuilder AddBackOfficeAuthorizationPolicies(this IUmbracoBuilder builder, string backOfficeAuthenticationScheme = Umbraco.Core.Constants.Security.BackOfficeAuthenticationType) { builder.Services.AddBackOfficeAuthorizationPolicies(backOfficeAuthenticationScheme); + // TODO: See other TODOs in things like UmbracoApiControllerBase ... AFAIK all of this is only used for the back office // so IMO these controllers and the features auth policies should just be moved to the back office project and then this // ext method can be removed. @@ -70,6 +88,9 @@ namespace Umbraco.Extensions return builder; } + /// + /// Adds Umbraco preview support + /// public static IUmbracoBuilder AddPreviewSupport(this IUmbracoBuilder builder) { builder.Services.AddSignalR(); diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoBuilderExtensions.cs similarity index 93% rename from src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs rename to src/Umbraco.Web.Common/Extensions/UmbracoBuilderExtensions.cs index 445025a80c..80185f30a3 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoBuilderExtensions.cs @@ -18,11 +18,13 @@ using Microsoft.Extensions.Options; using Serilog; using Smidge; using Smidge.Nuglify; +using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.Models.Validation; +using Umbraco.Core.DependencyInjection; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -34,15 +36,20 @@ using Umbraco.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Infrastructure.Runtime; using Umbraco.Web.Common.ApplicationModels; using Umbraco.Web.Common.AspNetCore; +using Umbraco.Web.Common.Extensions; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.Common.Profiler; using Umbraco.Web.Telemetry; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; -namespace Umbraco.Core.DependencyInjection +namespace Umbraco.Web.Common.Extensions { // TODO: We could add parameters to configure each of these for flexibility + + /// + /// Extension methods for for the common Umbraco functionality + /// public static class UmbracoBuilderExtensions { public static IUmbracoBuilder AddUmbraco( @@ -62,7 +69,7 @@ namespace Umbraco.Core.DependencyInjection IHostingEnvironment tempHostingEnvironment = GetTemporaryHostingEnvironment(webHostEnvironment, config); - var loggingDir = tempHostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.LogFiles); + var loggingDir = tempHostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.LogFiles); var loggingConfig = new LoggingConfiguration(loggingDir); services.AddLogger(tempHostingEnvironment, loggingConfig, config); @@ -72,10 +79,10 @@ namespace Umbraco.Core.DependencyInjection var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); var appCaches = AppCaches.Create(requestCache); - services.AddUnique(appCaches); + services.AddUnique(appCaches); IProfiler profiler = GetWebProfiler(config); - services.AddUnique(profiler); + services.AddUnique(profiler); ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); TypeLoader typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, tempHostingEnvironment, loggerFactory, appCaches, config, profiler); @@ -102,7 +109,7 @@ namespace Umbraco.Core.DependencyInjection factory.GetServices() )); - builder.Services.AddUnique(factory => + builder.Services.AddUnique(factory => { var globalSettings = factory.GetRequiredService>().Value; var connectionStrings = factory.GetRequiredService>().Value; @@ -135,20 +142,20 @@ namespace Umbraco.Core.DependencyInjection } ); - builder.Services.AddUnique(factory => factory.GetRequiredService().RuntimeCache); - builder.Services.AddUnique(factory => factory.GetRequiredService().RequestCache); + 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(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.Services.AddHostedService(factory => factory.GetRequiredService()); builder.AddCoreInitialServices(); builder.AddComposers(); @@ -201,7 +208,6 @@ namespace Umbraco.Core.DependencyInjection return builder; } - public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder) { builder.Services.AddHostedService(); @@ -235,8 +241,8 @@ namespace Umbraco.Core.DependencyInjection { // TODO: We need to figure out if we can work around this because calling AddControllersWithViews modifies the global app and order is very important // this will directly affect developers who need to call that themselves. - //We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. - //But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. + // We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. + // But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. var mvcBuilder = builder.Services.AddControllersWithViews(options => { options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/Extensions/WebsiteUmbracoBuilderExtensions.cs similarity index 87% rename from src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs rename to src/Umbraco.Web.Website/Extensions/WebsiteUmbracoBuilderExtensions.cs index cbfa0c659e..204f97ae30 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/WebsiteUmbracoBuilderExtensions.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core.DependencyInjection; +using Umbraco.Infrastructure.PublishedCache.Extensions; using Umbraco.Web.Website.Controllers; using Umbraco.Web.Website.Routing; using Umbraco.Web.Website.ViewEngines; @@ -11,12 +12,12 @@ namespace Umbraco.Extensions /// /// extensions for umbraco front-end website /// - public static class UmbracoBuilderExtensions + public static class WebsiteUmbracoBuilderExtensions { /// /// Add services for the umbraco front-end website /// - public static IUmbracoBuilder AddUmbracoWebsite(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddWebsite(this IUmbracoBuilder builder) { // Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection // to inject dependencies into the viewEngines) @@ -34,6 +35,8 @@ namespace Umbraco.Extensions builder.Services.AddScoped(); builder.Services.AddSingleton(); + builder.AddNuCache(); + return builder; }