diff --git a/src/Umbraco.Core/Builder/IUmbracoBuilder.cs b/src/Umbraco.Core/Builder/IUmbracoBuilder.cs new file mode 100644 index 0000000000..4659be55f1 --- /dev/null +++ b/src/Umbraco.Core/Builder/IUmbracoBuilder.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; + +namespace Umbraco.Core.Builder +{ + public interface IUmbracoBuilder + { + IServiceCollection Services { get; } + IConfiguration Config { get; } + TypeLoader TypeLoader { get; } + ILoggerFactory BuilderLoggerFactory { get; } + TBuilder WithCollectionBuilder() where TBuilder : ICollectionBuilder, new(); + void Build(); + } +} diff --git a/src/Umbraco.Core/Builder/UmbracoBuilder.cs b/src/Umbraco.Core/Builder/UmbracoBuilder.cs new file mode 100644 index 0000000000..9514b0de59 --- /dev/null +++ b/src/Umbraco.Core/Builder/UmbracoBuilder.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Umbraco.Core.Builder; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Common.Builder +{ + 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 UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader) + : this(services, config, typeLoader, NullLoggerFactory.Instance) + { } + + public UmbracoBuilder(IServiceCollection services, IConfiguration config, TypeLoader typeLoader, ILoggerFactory loggerFactory) + { + Services = services; + Config = config; + BuilderLoggerFactory = loggerFactory; + TypeLoader = typeLoader; + } + + /// + /// Gets a collection builder (and registers the collection). + /// + /// The type of the collection builder. + /// The collection builder. + public TBuilder WithCollectionBuilder() + where TBuilder : ICollectionBuilder, new() + { + var typeOfBuilder = typeof(TBuilder); + + if (_builders.TryGetValue(typeOfBuilder, out var o)) + return (TBuilder)o; + + var builder = new TBuilder(); + _builders[typeOfBuilder] = builder; + return builder; + } + + public void Build() + { + foreach (var builder in _builders.Values) + builder.RegisterWith(Services); + + _builders.Clear(); + } + } +} diff --git a/src/Umbraco.Core/Cache/AppCaches.cs b/src/Umbraco.Core/Cache/AppCaches.cs index 8930320447..2d482756c1 100644 --- a/src/Umbraco.Core/Cache/AppCaches.cs +++ b/src/Umbraco.Core/Cache/AppCaches.cs @@ -64,5 +64,13 @@ namespace Umbraco.Core.Cache /// search through all keys on a global scale. /// public IsolatedCaches IsolatedCaches { get; } + + public static AppCaches Create(IRequestCache requestCache) + { + return new AppCaches( + new DeepCloneAppCache(new ObjectCacheAppCache()), + requestCache, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); + } } } diff --git a/src/Umbraco.Core/Composing/ComponentComposer.cs b/src/Umbraco.Core/Composing/ComponentComposer.cs index 72f9dfe5e2..8092b58c79 100644 --- a/src/Umbraco.Core/Composing/ComponentComposer.cs +++ b/src/Umbraco.Core/Composing/ComponentComposer.cs @@ -1,4 +1,6 @@  +using Umbraco.Core.Builder; + namespace Umbraco.Core.Composing { /// @@ -9,9 +11,9 @@ namespace Umbraco.Core.Composing where TComponent : IComponent { /// - public virtual void Compose(Composition composition) + public virtual void Compose(IUmbracoBuilder builder) { - composition.Components().Append(); + builder.Components().Append(); } // note: thanks to this class, a component that does not compose anything can be diff --git a/src/Umbraco.Core/Composing/Composers.cs b/src/Umbraco.Core/Composing/Composers.cs index 31c02a08fe..caef92f90a 100644 --- a/src/Umbraco.Core/Composing/Composers.cs +++ b/src/Umbraco.Core/Composing/Composers.cs @@ -6,6 +6,7 @@ using System.Text; using Umbraco.Core.Collections; using Umbraco.Core.Logging; using Microsoft.Extensions.Logging; +using Umbraco.Core.Builder; namespace Umbraco.Core.Composing { @@ -16,9 +17,8 @@ namespace Umbraco.Core.Composing /// public class Composers { - private readonly Composition _composition; + private readonly IUmbracoBuilder _builder; private readonly ILogger _logger; - private readonly IProfilingLogger _profileLogger; private readonly IEnumerable _composerTypes; private readonly IEnumerable _enableDisableAttributes; @@ -27,7 +27,7 @@ namespace Umbraco.Core.Composing /// /// Initializes a new instance of the class. /// - /// The composition. + /// The composition. /// The types. /// The and/or attributes. /// The logger. @@ -39,13 +39,12 @@ namespace Umbraco.Core.Composing /// enableDisableAttributes /// or /// logger - public Composers(Composition composition, IEnumerable composerTypes, IEnumerable enableDisableAttributes, ILogger logger, IProfilingLogger profileLogger) + public Composers(IUmbracoBuilder builder, IEnumerable composerTypes, IEnumerable enableDisableAttributes, ILogger logger) { - _composition = composition ?? throw new ArgumentNullException(nameof(composition)); + _builder = builder ?? throw new ArgumentNullException(nameof(builder)); _composerTypes = composerTypes ?? throw new ArgumentNullException(nameof(composerTypes)); _enableDisableAttributes = enableDisableAttributes ?? throw new ArgumentNullException(nameof(enableDisableAttributes)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _profileLogger = profileLogger; } private class EnableInfo @@ -60,27 +59,19 @@ namespace Umbraco.Core.Composing public void Compose() { // make sure it is there - _composition.WithCollectionBuilder(); + _builder.WithCollectionBuilder(); IEnumerable orderedComposerTypes; - using (_profileLogger.DebugDuration("Preparing composer types.", "Prepared composer types.")) - { - orderedComposerTypes = PrepareComposerTypes(); - } + orderedComposerTypes = PrepareComposerTypes(); var composers = InstantiateComposers(orderedComposerTypes); - using (_profileLogger.DebugDuration($"Composing composers. (log when >{LogThresholdMilliseconds}ms)", "Composed composers.")) + + foreach (var composer in composers) { - foreach (var composer in composers) - { - var componentType = composer.GetType(); - using (_profileLogger.DebugDuration($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) - { - composer.Compose(_composition); - } - } + var componentType = composer.GetType(); + composer.Compose(_builder); } } @@ -359,13 +350,10 @@ namespace Umbraco.Core.Composing var ctor = type.GetConstructor(Array.Empty()); if (ctor == null) throw new InvalidOperationException($"Composer {type.FullName} does not have a parameter-less constructor."); - return (IComposer) ctor.Invoke(Array.Empty()); + return (IComposer)ctor.Invoke(Array.Empty()); } - using (_profileLogger.DebugDuration("Instantiating composers.", "Instantiated composers.")) - { - return types.Select(InstantiateComposer).ToArray(); - } + return types.Select(InstantiateComposer).ToArray(); } } } diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs deleted file mode 100644 index fcadf7dd1b..0000000000 --- a/src/Umbraco.Core/Composing/Composition.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core.Cache; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; - -namespace Umbraco.Core.Composing -{ - /// - /// Represents a composition. - /// - /// Although a composition exposes the application's service container, people should use the - /// extension methods (such as PropertyEditors() or SetPublishedContentModelFactory()) and - /// avoid accessing the container. This is because everything needs to be properly registered and with - /// the proper lifecycle. These methods will take care of it. Directly registering into the container - /// may cause issues. - public class Composition - { - public TypeLoader TypeLoader { get; } - public IRuntimeState RuntimeState { get; } - public IProfilingLogger Logger { get; } - public IIOHelper IOHelper { get; } - public AppCaches AppCaches { get; } - public IServiceCollection Services { get; } - - private readonly Dictionary _builders = new Dictionary(); - - public Composition(IServiceCollection services, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, IIOHelper ioHelper, AppCaches appCaches) - { - Services = services ?? throw new ArgumentNullException(nameof(services)); - TypeLoader = typeLoader ?? throw new ArgumentNullException(nameof(typeLoader)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - RuntimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); - IOHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); - AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); - } - - public void RegisterBuilders() - { - foreach (var builder in _builders.Values) - builder.RegisterWith(Services); - _builders.Clear(); // no point keep them around - } - - /// - /// Gets a collection builder (and registers the collection). - /// - /// The type of the collection builder. - /// The collection builder. - public TBuilder WithCollectionBuilder() - where TBuilder: ICollectionBuilder, new() - { - var typeOfBuilder = typeof(TBuilder); - - if (_builders.TryGetValue(typeOfBuilder, out var o)) - return (TBuilder) o; - - var builder = new TBuilder(); - _builders[typeOfBuilder] = builder; - return builder; - } - } -} diff --git a/src/Umbraco.Core/Composing/CompositionExtensions.cs b/src/Umbraco.Core/Composing/CompositionExtensions.cs index b3dc4301c3..ff99142c2c 100644 --- a/src/Umbraco.Core/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Core/Composing/CompositionExtensions.cs @@ -1,5 +1,6 @@ using System; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Web.PublishedCache; @@ -10,32 +11,32 @@ namespace Umbraco.Infrastructure.PublishedCache /// /// Sets the published snapshot service. /// - /// The composition. + /// The builder. /// A function creating a published snapshot service. - public static void SetPublishedSnapshotService(this Composition composition, Func factory) + public static void SetPublishedSnapshotService(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the published snapshot service. /// /// The type of the published snapshot service. - /// The composition. - public static void SetPublishedSnapshotService(this Composition composition) + /// The builder. + public static void SetPublishedSnapshotService(this IUmbracoBuilder builder) where T : class, IPublishedSnapshotService { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the published snapshot service. /// - /// The composition. + /// The builder. /// A published snapshot service. - public static void SetPublishedSnapshotService(this Composition composition, IPublishedSnapshotService service) + public static void SetPublishedSnapshotService(this IUmbracoBuilder builder, IPublishedSnapshotService service) { - composition.Services.AddUnique(_ => service); + builder.Services.AddUnique(service); } } } diff --git a/src/Umbraco.Core/Composing/IComposer.cs b/src/Umbraco.Core/Composing/IComposer.cs index b73a745b61..6ba21eff4e 100644 --- a/src/Umbraco.Core/Composing/IComposer.cs +++ b/src/Umbraco.Core/Composing/IComposer.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Composing +using Umbraco.Core.Builder; + +namespace Umbraco.Core.Composing { /// /// Represents a composer. @@ -8,6 +10,6 @@ /// /// Compose. /// - void Compose(Composition composition); + void Compose(IUmbracoBuilder builder); } } diff --git a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs index 8b5af064af..c5a994c9a6 100644 --- a/src/Umbraco.Core/Composing/RuntimeHashPaths.cs +++ b/src/Umbraco.Core/Composing/RuntimeHashPaths.cs @@ -11,7 +11,12 @@ namespace Umbraco.Core.Composing private readonly List _paths = new List(); private readonly Dictionary _files = new Dictionary(); - public void AddFolder(DirectoryInfo pathInfo) => _paths.Add(pathInfo); + public RuntimeHashPaths AddFolder(DirectoryInfo pathInfo) + { + _paths.Add(pathInfo); + return this; + } + public void AddFile(FileInfo fileInfo, bool scanFileContent = false) => _files.Add(fileInfo, scanFileContent); public IEnumerable GetFolders() => _paths; diff --git a/src/Umbraco.Core/Composing/TypeFinderConfig.cs b/src/Umbraco.Core/Composing/TypeFinderConfig.cs index 302d45b4e8..ef862fd49d 100644 --- a/src/Umbraco.Core/Composing/TypeFinderConfig.cs +++ b/src/Umbraco.Core/Composing/TypeFinderConfig.cs @@ -15,9 +15,9 @@ namespace Umbraco.Core.Composing private readonly TypeFinderSettings _settings; private IEnumerable _assembliesAcceptingLoadExceptions; - public TypeFinderConfig(IOptionsMonitor settings) + public TypeFinderConfig(IOptions settings) { - _settings = settings.CurrentValue; + _settings = settings.Value; } public IEnumerable AssembliesAcceptingLoadExceptions diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs index 218e2a04e3..d6c73478bf 100644 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ b/src/Umbraco.Core/CompositionExtensions.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Composing; +using Umbraco.Core.Builder; +using Umbraco.Core.Composing; using Umbraco.Core.HealthCheck; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; @@ -20,82 +21,82 @@ namespace Umbraco.Core /// /// Gets the actions collection builder. /// - /// The composition. + /// The builder. /// - public static ActionCollectionBuilder Actions(this Composition composition) - => composition.WithCollectionBuilder(); + public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the content apps collection builder. /// - /// The composition. + /// The builder. /// - public static ContentAppFactoryCollectionBuilder ContentApps(this Composition composition) - => composition.WithCollectionBuilder(); + public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the content finders collection builder. /// - /// The composition. + /// The builder. /// - public static ContentFinderCollectionBuilder ContentFinders(this Composition composition) - => composition.WithCollectionBuilder(); + public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the editor validators collection builder. /// - /// The composition. + /// The builder. /// - public static EditorValidatorCollectionBuilder EditorValidators(this Composition composition) - => composition.WithCollectionBuilder(); + public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the health checks collection builder. /// - /// The composition. - public static HealthCheckCollectionBuilder HealthChecks(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the TourFilters collection builder. /// - public static TourFilterCollectionBuilder TourFilters(this Composition composition) - => composition.WithCollectionBuilder(); + public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the url providers collection builder. /// - /// The composition. - public static UrlProviderCollectionBuilder UrlProviders(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the media url providers collection builder. /// - /// The composition. - public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the backoffice sections/applications collection builder. /// - /// The composition. - public static SectionCollectionBuilder Sections(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the components collection builder. /// - public static ComponentCollectionBuilder Components(this Composition composition) - => composition.WithCollectionBuilder(); + public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the backoffice dashboards collection builder. /// - /// The composition. - public static DashboardCollectionBuilder Dashboards(this Composition composition) - => composition.WithCollectionBuilder() + /// The builder. + public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder() .Add() .Add() .Add() @@ -112,10 +113,10 @@ namespace Umbraco.Core /// /// Gets the content finders collection builder. /// - /// The composition. + /// The builder. /// - public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this Composition composition) - => composition.WithCollectionBuilder(); + public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); #endregion } diff --git a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs index 7884126dc8..738da5ef60 100644 --- a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs +++ b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs @@ -5,24 +5,25 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; namespace Umbraco.Web.ContentApps { public class ContentAppFactoryCollection : BuilderCollectionBase { private readonly ILogger _logger; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; - public ContentAppFactoryCollection(IEnumerable items, ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) + public ContentAppFactoryCollection(IEnumerable items, ILogger logger, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) : base(items) { _logger = logger; - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; } private IEnumerable GetCurrentUserGroups() { - var currentUser = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser; + var currentUser = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser; return currentUser == null ? Enumerable.Empty() : currentUser.Groups; diff --git a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs index 0f0e09042b..138c426043 100644 --- a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs +++ b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs @@ -9,6 +9,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Manifest; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Identity; +using Umbraco.Core.Security; namespace Umbraco.Web.ContentApps { @@ -21,8 +22,8 @@ namespace Umbraco.Web.ContentApps { // get the logger factory just-in-time - see note below for manifest parser var loggerFactory = factory.GetRequiredService(); - var umbracoContextAccessor = factory.GetRequiredService(); - return new ContentAppFactoryCollection(CreateItems(factory), loggerFactory.CreateLogger(), umbracoContextAccessor); + var backOfficeSecurityAccessor = factory.GetRequiredService(); + return new ContentAppFactoryCollection(CreateItems(factory), loggerFactory.CreateLogger(), backOfficeSecurityAccessor); } protected override IEnumerable CreateItems(IServiceProvider factory) diff --git a/src/Umbraco.Core/IUmbracoContext.cs b/src/Umbraco.Core/IUmbracoContext.cs index 312135169a..681dedbfd2 100644 --- a/src/Umbraco.Core/IUmbracoContext.cs +++ b/src/Umbraco.Core/IUmbracoContext.cs @@ -15,11 +15,6 @@ namespace Umbraco.Web /// DateTime ObjectCreated { get; } - /// - /// Gets the BackofficeSecurity class - /// - IBackOfficeSecurity Security { get; } - /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. /// diff --git a/src/Umbraco.Core/Logging/ProfilingLogger.cs b/src/Umbraco.Core/Logging/ProfilingLogger.cs index 7bf04e3d77..520e14e17d 100644 --- a/src/Umbraco.Core/Logging/ProfilingLogger.cs +++ b/src/Umbraco.Core/Logging/ProfilingLogger.cs @@ -23,7 +23,7 @@ namespace Umbraco.Core.Logging /// /// Initializes a new instance of the class. /// - public ProfilingLogger(ILogger logger, IProfiler profiler) + public ProfilingLogger(ILogger logger, IProfiler profiler) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); Profiler = profiler ?? throw new ArgumentNullException(nameof(profiler)); diff --git a/src/Umbraco.Core/Models/LoginModel.cs b/src/Umbraco.Core/Models/Security/LoginModel.cs similarity index 82% rename from src/Umbraco.Core/Models/LoginModel.cs rename to src/Umbraco.Core/Models/Security/LoginModel.cs index f44b274ffb..98c9d23cff 100644 --- a/src/Umbraco.Core/Models/LoginModel.cs +++ b/src/Umbraco.Core/Models/Security/LoginModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { public class LoginModel : PostRedirectModel { @@ -11,7 +11,7 @@ namespace Umbraco.Web.Models [Required] [DataMember(Name = "password", IsRequired = true)] - [StringLength(maximumLength:256)] + [StringLength(maximumLength: 256)] public string Password { get; set; } } diff --git a/src/Umbraco.Web/Models/LoginStatusModel.cs b/src/Umbraco.Core/Models/Security/LoginStatusModel.cs similarity index 96% rename from src/Umbraco.Web/Models/LoginStatusModel.cs rename to src/Umbraco.Core/Models/Security/LoginStatusModel.cs index 4b699bab38..3978a84334 100644 --- a/src/Umbraco.Web/Models/LoginStatusModel.cs +++ b/src/Umbraco.Core/Models/Security/LoginStatusModel.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; - -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { /// /// The model representing the status of a logged in member. diff --git a/src/Umbraco.Core/Models/PostRedirectModel.cs b/src/Umbraco.Core/Models/Security/PostRedirectModel.cs similarity index 92% rename from src/Umbraco.Core/Models/PostRedirectModel.cs rename to src/Umbraco.Core/Models/Security/PostRedirectModel.cs index e04584704d..3a87cdcbe5 100644 --- a/src/Umbraco.Core/Models/PostRedirectModel.cs +++ b/src/Umbraco.Core/Models/Security/PostRedirectModel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { /// /// A base model containing a value to indicate to Umbraco where to redirect to after Posting if diff --git a/src/Umbraco.Web/Models/ProfileModel.cs b/src/Umbraco.Core/Models/Security/ProfileModel.cs similarity index 62% rename from src/Umbraco.Web/Models/ProfileModel.cs rename to src/Umbraco.Core/Models/Security/ProfileModel.cs index 0397f34849..8493a5f5a9 100644 --- a/src/Umbraco.Web/Models/ProfileModel.cs +++ b/src/Umbraco.Core/Models/Security/ProfileModel.cs @@ -2,36 +2,15 @@ using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Web.Mvc; -using Current = Umbraco.Web.Composing.Current; +using Umbraco.Web.Models; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { /// /// A readonly member profile model /// - [ModelBinder(typeof(ProfileModelBinder))] public class ProfileModel : PostRedirectModel { - - public static ProfileModel CreateModel() - { - var model = new ProfileModel(false); - return model; - } - - private ProfileModel(bool doLookup) - { - MemberProperties = new List(); - if (doLookup && Current.UmbracoContext != null) - { - var helper = Current.MembershipHelper; - var model = helper.GetCurrentMemberProfileModel(); - MemberProperties = model.MemberProperties; - } - } - - [Required] [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", ErrorMessage = "Please enter a valid e-mail address")] @@ -81,18 +60,6 @@ namespace Umbraco.Web.Models /// /// Adding items to this list on the front-end will not add properties to the member in the database. /// - public List MemberProperties { get; set; } - - /// - /// A custom model binder for MVC because the default ctor performs a lookup! - /// - internal class ProfileModelBinder : DefaultModelBinder - { - protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) - { - return ProfileModel.CreateModel(); - } - - } + public List MemberProperties { get; set; } = new List(); } } diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Core/Models/Security/RegisterModel.cs similarity index 79% rename from src/Umbraco.Web/Models/RegisterModel.cs rename to src/Umbraco.Core/Models/Security/RegisterModel.cs index 1ee9307969..fca749703d 100644 --- a/src/Umbraco.Web/Models/RegisterModel.cs +++ b/src/Umbraco.Core/Models/Security/RegisterModel.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Web.Mvc; -using Umbraco.Core; +using Umbraco.Web.Models; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { - [ModelBinder(typeof(RegisterModelBinder))] public class RegisterModel : PostRedirectModel { /// @@ -27,7 +24,6 @@ namespace Umbraco.Web.Models CreatePersistentLoginCookie = true; } - [Required] [RegularExpression(@"[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?", ErrorMessage = "Please enter a valid e-mail address")] @@ -74,16 +70,5 @@ namespace Umbraco.Web.Models /// Default is true to create a persistent cookie if LoginOnSuccess is true /// public bool CreatePersistentLoginCookie { get; set; } - - /// - /// A custom model binder for MVC because the default ctor performs a lookup! - /// - internal class RegisterModelBinder : DefaultModelBinder - { - protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) - { - return RegisterModel.CreateModel(); - } - } } } diff --git a/src/Umbraco.Core/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs similarity index 98% rename from src/Umbraco.Core/ConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs index 43de192914..e40db6e3cd 100644 --- a/src/Umbraco.Core/ConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; -namespace Umbraco.Core +namespace Umbraco.Core.PropertyEditors { /// /// Represents a data type configuration editor. diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs similarity index 92% rename from src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs rename to src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs index 2737dcfef1..1dadd6cf0a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors //TODO: We will need to change this once we support tracking via variants/segments // for now, we are tracking values from ALL variants - foreach(var propertyVal in p.Values) + foreach (var propertyVal in p.Values) { var val = propertyVal.EditedValue; @@ -33,9 +33,9 @@ namespace Umbraco.Core.PropertyEditors if (valueEditor is IDataValueReference reference) { var refs = reference.GetReferences(val); - foreach(var r in refs) + foreach (var r in refs) trackedRelations.Add(r); - } + } // Loop over collection that may be add to existing property editors // implementation of GetReferences in IDataValueReference. @@ -48,14 +48,11 @@ namespace Umbraco.Core.PropertyEditors // in the dataeditor/property has referecnes to media/content items if (item.IsForEditor(editor)) { - foreach(var r in item.GetDataValueReference().GetReferences(val)) + foreach (var r in item.GetDataValueReference().GetReferences(val)) trackedRelations.Add(r); } - } } - - } return trackedRelations; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs rename to src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs index 207a82844d..efb1df1eb7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors @@ -7,7 +6,7 @@ namespace Umbraco.Web.PropertyEditors /// /// A custom pre-value editor class to deal with the legacy way that the pre-value data is stored. /// - internal class DecimalConfigurationEditor : ConfigurationEditor + public class DecimalConfigurationEditor : ConfigurationEditor { public DecimalConfigurationEditor() { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs b/src/Umbraco.Core/PropertyEditors/IDataValueReference.cs similarity index 96% rename from src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs rename to src/Umbraco.Core/PropertyEditors/IDataValueReference.cs index 6377098bfc..8c0806a4a4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueReference.cs @@ -13,6 +13,6 @@ namespace Umbraco.Core.PropertyEditors /// /// /// - IEnumerable GetReferences(object value); + IEnumerable GetReferences(object value); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs b/src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs rename to src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs index 6587e071bf..c13c1ed212 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs @@ -5,7 +5,7 @@ /// /// Gets a value indicating whether the DataValueReference lookup supports a datatype (data editor). /// - /// The datatype. + /// /// A value indicating whether the converter supports a datatype. bool IsForEditor(IDataEditor dataEditor); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs index e80c0fcb0e..bb1f8af790 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors @@ -7,7 +6,7 @@ namespace Umbraco.Web.PropertyEditors /// /// A custom pre-value editor class to deal with the legacy way that the pre-value data is stored. /// - internal class IntegerConfigurationEditor : ConfigurationEditor + public class IntegerConfigurationEditor : ConfigurationEditor { public IntegerConfigurationEditor() { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs similarity index 84% rename from src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs index ce41628ec1..083e36029e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -31,7 +31,7 @@ namespace Umbraco.Web.PropertyEditors new Layout { Name = "grid", Icon = "icon-thumbnails-small", IsSystem = 1, Selected = true, Path = "views/propertyeditors/listview/layouts/grid/grid.html" } }; - IncludeProperties = new [] + IncludeProperties = new[] { new Property { Alias = "sortOrder", Header = "Sort order", IsSystem = 1 }, new Property { Alias = "updateDate", Header = "Last edited", IsSystem = 1 }, @@ -41,7 +41,7 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - + [ConfigurationField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", Description = "The default sort order for the list")] public string OrderBy { get; set; } @@ -69,54 +69,57 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("showContentFirst", "Show Content App First", "boolean", Description = "Enable this to show the content app by default instead of the list view app")] public bool ShowContentFirst { get; set; } + [DataContract] public class Property { - [JsonProperty("alias")] + [DataMember(Name = "alias")] public string Alias { get; set; } - [JsonProperty("header")] + [DataMember(Name = "header")] public string Header { get; set; } - [JsonProperty("nameTemplate")] + [DataMember(Name = "nameTemplate")] public string Template { get; set; } - [JsonProperty("isSystem")] + [DataMember(Name = "isSystem")] public int IsSystem { get; set; } // TODO: bool } + [DataContract] public class Layout { - [JsonProperty("name")] + [DataMember(Name = "name")] public string Name { get; set; } - [JsonProperty("path")] + [DataMember(Name = "path")] public string Path { get; set; } - [JsonProperty("icon")] + [DataMember(Name = "icon")] public string Icon { get; set; } - [JsonProperty("isSystem")] + [DataMember(Name = "isSystem")] public int IsSystem { get; set; } // TODO: bool - [JsonProperty("selected")] + [DataMember(Name = "selected")] public bool Selected { get; set; } } + [DataContract] public class BulkActionPermissionSettings { - [JsonProperty("allowBulkPublish")] + [DataMember(Name = "allowBulkPublish")] public bool AllowBulkPublish { get; set; } = true; - [JsonProperty("allowBulkUnpublish")] + [DataMember(Name = "allowBulkUnpublish")] public bool AllowBulkUnpublish { get; set; } = true; - [JsonProperty("allowBulkCopy")] + [DataMember(Name = "allowBulkCopy")] public bool AllowBulkCopy { get; set; } = true; - [JsonProperty("allowBulkMove")] + [DataMember(Name = "allowBulkMove")] public bool AllowBulkMove { get; set; } = true; - [JsonProperty("allowBulkDelete")] + [DataMember(Name = "allowBulkDelete")] public bool AllowBulkDelete { get; set; } = true; } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs similarity index 89% rename from src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs index 255be498bc..ba7dea6548 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Umbraco.Core; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MissingPropertyEditor.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/MissingPropertyEditor.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfiguration.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/MultiNodePickerConfiguration.cs diff --git a/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs new file mode 100644 index 0000000000..749f46abc5 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; +using Umbraco.Core; + +namespace Umbraco.Web.PropertyEditors +{ + /// + /// Represents the 'startNode' value for the + /// + [DataContract] + public class MultiNodePickerConfigurationTreeSource + { + [DataMember(Name = "type")] + public string ObjectType { get; set; } + + [DataMember(Name = "query")] + public string StartNodeQuery { get; set; } + + [DataMember(Name = "id")] + public Udi StartNodeId { get; set; } + } +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs b/src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs similarity index 88% rename from src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs index 89190883c8..e75be48f36 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -27,15 +27,17 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("hideLabel", "Hide Label", "boolean", Description = "Hide the property label and let the item list span the full width of the editor window.")] public bool HideLabel { get; set; } + + [DataContract] public class ContentType { - [JsonProperty("ncAlias")] + [DataMember(Name = "ncAlias")] public string Alias { get; set; } - [JsonProperty("ncTabAlias")] + [DataMember(Name = "ncTabAlias")] public string TabAlias { get; set; } - [JsonProperty("nameTemplate")] + [DataMember(Name = "nameTemplate")] public string Template { get; set; } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs similarity index 95% rename from src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs index 88eb1d224e..bf3cd197a3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs similarity index 98% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs index 8b3655f0cc..99bbe86dae 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs @@ -27,7 +27,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters => propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ContentPicker); public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (IPublishedContent); + => typeof(IPublishedContent); public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Elements; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs similarity index 95% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index eb461b4920..e706c198cf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -65,9 +65,9 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters if (source is decimal sourceDecimal) return sourceDecimal; if (source is string sourceDecimalString) return decimal.TryParse(sourceDecimalString, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) ? d : 0; - if (source is double sourceDouble) - return Convert.ToDecimal(sourceDouble); - return (decimal) 0; + if (source is double sourceDouble) + return Convert.ToDecimal(sourceDouble); + return (decimal)0; case ValueTypes.Integer: if (source is int sourceInt) return sourceInt; if (source is string sourceIntString) @@ -76,7 +76,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters case ValueTypes.Bigint: if (source is string sourceLongString) return long.TryParse(sourceLongString, out var i) ? i : 0; - return (long) 0; + return (long)0; default: // everything else is a string return source?.ToString() ?? string.Empty; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs similarity index 98% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index 5405727791..9a33fd56e5 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Web.PublishedCache; + namespace Umbraco.Web.PropertyEditors.ValueConverters { /// @@ -67,7 +68,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var isMultiple = IsMultipleDataType(propertyType.DataType); - var udis = (Udi[]) source; + var udis = (Udi[])source; var mediaItems = new List(); if (source == null) return isMultiple ? mediaItems : null; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs similarity index 97% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs index c4e384e1e8..51471f6da7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters => propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce; public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (IHtmlEncodedString); + => typeof(IHtmlEncodedString); // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs index 1b7c460c8b..fd353f95cd 100644 --- a/src/Umbraco.Core/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/PublishedContentExtensions.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; -using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; diff --git a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs similarity index 72% rename from src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs rename to src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs index 4549227c89..eb4be355f4 100644 --- a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs +++ b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs @@ -1,15 +1,12 @@ using Umbraco.Core.Cache; -using Umbraco.Core.Security; using Umbraco.Web; -using Umbraco.Web.Security; -namespace Umbraco.Core +namespace Umbraco.Core.Security { - public class HybridBackofficeSecurityAccessor : HybridAccessorBase, IBackOfficeSecurityAccessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public HybridBackofficeSecurityAccessor(IRequestCache requestCache) : base(requestCache) @@ -19,7 +16,7 @@ namespace Umbraco.Core protected override string ItemKey => "Umbraco.Web.HybridBackofficeSecurityAccessor"; /// - /// Gets or sets the object. + /// Gets or sets the object. /// public IBackOfficeSecurity BackOfficeSecurity { diff --git a/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs new file mode 100644 index 0000000000..09a7ab5d1b --- /dev/null +++ b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs @@ -0,0 +1,28 @@ +using Umbraco.Core.Cache; +using Umbraco.Web; + +namespace Umbraco.Core.Security +{ + + public class HybridUmbracoWebsiteSecurityAccessor : HybridAccessorBase, IUmbracoWebsiteSecurityAccessor + { + /// + /// Initializes a new instance of the class. + /// + public HybridUmbracoWebsiteSecurityAccessor(IRequestCache requestCache) + : base(requestCache) + { } + + /// + protected override string ItemKey => "Umbraco.Web.HybridUmbracoWebsiteSecurityAccessor"; + + /// + /// Gets or sets the object. + /// + public IUmbracoWebsiteSecurity WebsiteSecurity + { + get => Value; + set => Value = value; + } + } +} diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs new file mode 100644 index 0000000000..00124c4dce --- /dev/null +++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Umbraco.Core.Models.Security; + +namespace Umbraco.Core.Security +{ + public interface IUmbracoWebsiteSecurity + { + /// + /// Creates a model to use for registering new members with custom member properties + /// + /// Alias of member type for created member (default used if not provided). + /// Instance of + RegisterModel CreateRegistrationModel(string memberTypeAlias = null); + + /// + /// Registers a new member. + /// + /// Register member model. + /// Flag for whether to log the member in upon successful registration. + /// Result of registration operation. + Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true); + + /// + /// Creates a new profile model filled in with the current members details if they are logged in which allows for editing + /// profile properties. + /// + /// Instance of + Task GetCurrentMemberProfileModelAsync(); + + /// + /// Updates the currently logged in member's profile. + /// + /// Update member profile model. + /// Result of update profile operation. + Task UpdateMemberProfileAsync(ProfileModel model); + + /// + /// A helper method to perform the validation and logging in of a member. + /// + /// The username. + /// The password. + /// Result of login operation. + Task LoginAsync(string username, string password); + + /// + /// Check if a member is logged in + /// + /// True if logged in, false if not. + bool IsLoggedIn(); + + /// + /// Returns the login status model of the currently logged in member. + /// + /// Instance of + Task GetCurrentLoginStatusAsync(); + + /// + /// Logs out the current member. + /// + Task LogOutAsync(); + + /// + /// Checks if the current member is authorized based on the parameters provided. + /// + /// Allowed types. + /// Allowed groups. + /// Allowed individual members. + /// True or false if the currently logged in member is authorized + bool IsMemberAuthorized( + IEnumerable allowTypes = null, + IEnumerable allowGroups = null, + IEnumerable allowMembers = null); + } +} diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs new file mode 100644 index 0000000000..618aeb7146 --- /dev/null +++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Security +{ + public interface IUmbracoWebsiteSecurityAccessor + { + IUmbracoWebsiteSecurity WebsiteSecurity { get; set; } + } +} diff --git a/src/Umbraco.Core/Security/RegisterMemberStatus.cs b/src/Umbraco.Core/Security/RegisterMemberStatus.cs new file mode 100644 index 0000000000..1cbeae38d1 --- /dev/null +++ b/src/Umbraco.Core/Security/RegisterMemberStatus.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Security +{ + public enum RegisterMemberStatus + { + Success, + InvalidUserName, + InvalidPassword, + InvalidEmail, + DuplicateUserName, + DuplicateEmail, + Error, + } +} diff --git a/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs b/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs new file mode 100644 index 0000000000..1d435378a6 --- /dev/null +++ b/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core.Security +{ + public class UpdateMemberProfileResult + { + private UpdateMemberProfileResult() + { + } + + public UpdateMemberProfileStatus Status { get; private set; } + + public string ErrorMessage { get; private set; } + + public static UpdateMemberProfileResult Success() + { + return new UpdateMemberProfileResult { Status = UpdateMemberProfileStatus.Success }; + } + + public static UpdateMemberProfileResult Error(string message) + { + return new UpdateMemberProfileResult { Status = UpdateMemberProfileStatus.Error, ErrorMessage = message }; + } + } + +} diff --git a/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs b/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs new file mode 100644 index 0000000000..33dfe4d486 --- /dev/null +++ b/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Security +{ + public enum UpdateMemberProfileStatus + { + Success, + Error, + } +} diff --git a/src/Umbraco.Core/Services/IRuntimeState.cs b/src/Umbraco.Core/Services/IRuntimeState.cs index fd817f1986..ef826014be 100644 --- a/src/Umbraco.Core/Services/IRuntimeState.cs +++ b/src/Umbraco.Core/Services/IRuntimeState.cs @@ -55,5 +55,7 @@ namespace Umbraco.Core /// void DetermineRuntimeLevel(); + void Configure(RuntimeLevel level, RuntimeLevelReason reason); + } } diff --git a/src/Umbraco.Core/StaticApplicationLogging.cs b/src/Umbraco.Core/StaticApplicationLogging.cs index a1e06bc1f8..84cdc3c2d2 100644 --- a/src/Umbraco.Core/StaticApplicationLogging.cs +++ b/src/Umbraco.Core/StaticApplicationLogging.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core public static ILogger CreateLogger() { - return _loggerFactory?.CreateLogger() ?? new NullLogger(); + return _loggerFactory?.CreateLogger() ?? NullLoggerFactory.Instance.CreateLogger(); } } } diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index 24800fa98a..9551dc8b90 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using Examine; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web; using Umbraco.Web.Models.ContentEditing; @@ -16,19 +17,19 @@ namespace Umbraco.Examine { private readonly IExamineManager _examineManager; private readonly ILocalizationService _languageService; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IUmbracoTreeSearcherFields _treeSearcherFields; public BackOfficeExamineSearcher(IExamineManager examineManager, ILocalizationService languageService, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IEntityService entityService, IUmbracoTreeSearcherFields treeSearcherFields) { _examineManager = examineManager; _languageService = languageService; - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _entityService = entityService; _treeSearcherFields = treeSearcherFields; } @@ -47,7 +48,7 @@ namespace Umbraco.Examine query = "\"" + g.ToString() + "\""; } - var currentUser = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser; + var currentUser = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser; switch (entityType) { diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs index 5df99d86fb..a9bf887c16 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs @@ -1,5 +1,6 @@ using System.Runtime.InteropServices; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Examine @@ -8,18 +9,18 @@ namespace Umbraco.Examine [ComposeAfter(typeof(ICoreComposer))] public sealed class ExamineLuceneComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if(!isWindows) return; - base.Compose(composition); + base.Compose(builder); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs index 603819534f..bb9140634c 100644 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs +++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinderComposer.cs @@ -1,4 +1,5 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Web.Cache @@ -9,11 +10,11 @@ namespace Umbraco.Web.Cache [ComposeBefore(typeof(ICoreComposer))] // runs before every other IUmbracoCoreComponent! public sealed class DistributedCacheBinderComposer : ComponentComposer, ICoreComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs index 49dab2d1db..6f0a52d033 100644 --- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs @@ -1,6 +1,7 @@ using System; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; @@ -62,12 +63,12 @@ namespace Umbraco.Web.Compose }; } - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.SetDatabaseServerMessengerCallbacks(GetCallbacks); - composition.SetServerMessenger(); + builder.SetDatabaseServerMessengerCallbacks(GetCallbacks); + builder.SetServerMessenger(); } } diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs index 81a41cf575..8c26e0e688 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Web.Actions; @@ -183,7 +184,7 @@ namespace Umbraco.Web.Compose /// public sealed class Notifier { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IRequestAccessor _requestAccessor; private readonly INotificationService _notificationService; private readonly IUserService _userService; @@ -194,15 +195,15 @@ namespace Umbraco.Web.Compose /// /// Constructor /// - /// + /// + /// /// /// /// /// - /// /// public Notifier( - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IRequestAccessor requestAccessor, INotificationService notificationService, IUserService userService, @@ -210,7 +211,7 @@ namespace Umbraco.Web.Compose IOptions globalSettings, ILogger logger) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _requestAccessor = requestAccessor; _notificationService = notificationService; _userService = userService; @@ -221,7 +222,7 @@ namespace Umbraco.Web.Compose public void Notify(IAction action, params IContent[] entities) { - var user = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser; + var user = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser; //if there is no current user, then use the admin if (user == null) diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs index 44a5d58daa..e68d6dabf8 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComposer.cs @@ -1,15 +1,16 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Web.Compose { public sealed class NotificationsComposer : ComponentComposer, ICoreComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs index 823f8618ad..04f715c7c0 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/CoreMappingProfiles.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.BackOffice; +using Umbraco.Core.Builder; using Umbraco.Core.Mapping; using Umbraco.Web.Models.Mapping; @@ -11,13 +12,13 @@ namespace Umbraco.Core.Composing.CompositionExtensions /// /// Registers the core Umbraco mapper definitions /// - /// + /// /// - public static Composition ComposeCoreMappingProfiles(this Composition composition) + public static IUmbracoBuilder ComposeCoreMappingProfiles(this IUmbracoBuilder builder) { - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.WithCollectionBuilder() + builder.WithCollectionBuilder() .Add() .Add() .Add() @@ -37,10 +38,10 @@ namespace Umbraco.Core.Composing.CompositionExtensions .Add() ; - composition.Services.AddTransient(); - composition.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); - return composition; + return builder; } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs index a4286bd719..1f539782c7 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Core.Builder; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -33,21 +34,21 @@ namespace Umbraco.Core.Composing.CompositionExtensions * */ - public static Composition ComposeFileSystems(this Composition composition) + public static IUmbracoBuilder ComposeFileSystems(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. - composition.Services.AddUnique(factory => factory.CreateInstance(factory)); + builder.Services.AddUnique(factory => factory.CreateInstance(factory)); // register IFileSystems, which gives access too all filesystems - composition.Services.AddUnique(factory => factory.GetRequiredService()); + builder.Services.AddUnique(factory => factory.GetRequiredService()); // register the scheme for media paths - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.SetMediaFileSystem(factory => + builder.SetMediaFileSystem(factory => { var ioHelper = factory.GetRequiredService(); var hostingEnvironment = factory.GetRequiredService(); @@ -59,7 +60,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions return new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, rootPath, rootUrl); }); - return composition; + return builder; } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs index 7e64b0698c..e4272a44f3 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Installer.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Web.Install; using Umbraco.Web.Install.InstallSteps; @@ -9,28 +10,28 @@ namespace Umbraco.Web.Composing.CompositionExtensions { public static class Installer { - public static Composition ComposeInstaller(this Composition composition) + public static IUmbracoBuilder ComposeInstaller(this IUmbracoBuilder builder) { // register the installer steps - composition.Services.AddScoped(); - composition.Services.AddScoped(); - composition.Services.AddScoped(); - composition.Services.AddScoped(); - composition.Services.AddScoped(); - composition.Services.AddScoped(); + 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(); - composition.Services.AddScoped(); + builder.Services.AddScoped(); - composition.Services.AddTransient(); - composition.Services.AddUnique(); + builder.Services.AddTransient(); + builder.Services.AddUnique(); - return composition; + return builder; } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs index 8d15b5761a..ba4195faf0 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Builder; +using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; namespace Umbraco.Core.Composing.CompositionExtensions @@ -8,50 +9,50 @@ namespace Umbraco.Core.Composing.CompositionExtensions /// internal static class Repositories { - public static Composition ComposeRepositories(this Composition composition) + public static IUmbracoBuilder ComposeRepositories(this IUmbracoBuilder builder) { // repositories - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - return composition; + return builder; } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs index c6106b2191..f657236cad 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs @@ -4,6 +4,7 @@ using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; @@ -19,64 +20,64 @@ namespace Umbraco.Core.Composing.CompositionExtensions { internal static class Services { - public static Composition ComposeServices(this Composition composition) + public static IUmbracoBuilder ComposeServices(this IUmbracoBuilder builder) { // register a transient messages factory, which will be replaced by the web // boot manager when running in a web context - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register the service context - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register the special idk map - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register the services - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddTransient(SourcesFactory); - composition.Services.AddUnique(factory => new LocalizedTextService( + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddTransient(SourcesFactory); + builder.Services.AddUnique(factory => new LocalizedTextService( factory.GetRequiredService>(), factory.GetRequiredService>())); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(factory => CreatePackageRepository(factory, "createdPackages.config")); - composition.Services.AddUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => CreatePackageRepository(factory, "createdPackages.config")); + builder.Services.AddUnique(factory => CreatePackageRepository(factory, "installedPackages.config")); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - return composition; + return builder; } /// diff --git a/src/Umbraco.Infrastructure/CompositionExtensions.cs b/src/Umbraco.Infrastructure/CompositionExtensions.cs index 3a7537d346..d7a1c1125b 100644 --- a/src/Umbraco.Infrastructure/CompositionExtensions.cs +++ b/src/Umbraco.Infrastructure/CompositionExtensions.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Dictionary; @@ -27,80 +28,80 @@ namespace Umbraco.Core /// /// Gets the cache refreshers collection builder. /// - /// The composition. - public static CacheRefresherCollectionBuilder CacheRefreshers(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the mappers collection builder. /// - /// The composition. - public static MapperCollectionBuilder Mappers(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the package actions collection builder. /// - /// The composition. - internal static PackageActionCollectionBuilder PackageActions(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + internal static PackageActionCollectionBuilder PackageActions(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the data editor collection builder. /// - /// The composition. - public static DataEditorCollectionBuilder DataEditors(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the data value reference factory collection builder. /// - /// The composition. - public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the property value converters collection builder. /// - /// The composition. - public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the url segment providers collection builder. /// - /// The composition. - public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the validators collection builder. /// - /// The composition. - internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the manifest filter collection builder. /// - /// The composition. - public static ManifestFilterCollectionBuilder ManifestFilters(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the backoffice OEmbed Providers collection builder. /// - /// The composition. - public static EmbedProvidersCollectionBuilder OEmbedProviders(this Composition composition) - => composition.WithCollectionBuilder(); + /// The builder. + public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); /// /// Gets the back office searchable tree collection builder /// - /// + /// /// - public static SearchableTreeCollectionBuilder SearchableTrees(this Composition composition) - => composition.WithCollectionBuilder(); + public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); #endregion @@ -110,189 +111,189 @@ namespace Umbraco.Core /// Sets the culture dictionary factory. /// /// The type of the factory. - /// The composition. - public static void SetCultureDictionaryFactory(this Composition composition) + /// The builder. + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder) where T : class, ICultureDictionaryFactory { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the culture dictionary factory. /// - /// The composition. + /// The builder. /// A function creating a culture dictionary factory. - public static void SetCultureDictionaryFactory(this Composition composition, Func factory) + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the culture dictionary factory. /// - /// The composition. + /// The builder. /// A factory. - public static void SetCultureDictionaryFactory(this Composition composition, ICultureDictionaryFactory factory) + public static void SetCultureDictionaryFactory(this IUmbracoBuilder builder, ICultureDictionaryFactory factory) { - composition.Services.AddUnique(_ => factory); + builder.Services.AddUnique(factory); } /// /// Sets the published content model factory. /// /// The type of the factory. - /// The composition. - public static void SetPublishedContentModelFactory(this Composition composition) + /// The builder. + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder) where T : class, IPublishedModelFactory { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the published content model factory. /// - /// The composition. + /// The builder. /// A function creating a published content model factory. - public static void SetPublishedContentModelFactory(this Composition composition, Func factory) + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the published content model factory. /// - /// The composition. + /// The builder. /// A published content model factory. - public static void SetPublishedContentModelFactory(this Composition composition, IPublishedModelFactory factory) + public static void SetPublishedContentModelFactory(this IUmbracoBuilder builder, IPublishedModelFactory factory) { - composition.Services.AddUnique(_ => factory); + builder.Services.AddUnique(factory); } /// /// Sets the server registrar. /// /// The type of the server registrar. - /// The composition. - public static void SetServerRegistrar(this Composition composition) + /// The builder. + public static void SetServerRegistrar(this IUmbracoBuilder builder) where T : class, IServerRegistrar { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the server registrar. /// - /// The composition. + /// The builder. /// A function creating a server registrar. - public static void SetServerRegistrar(this Composition composition, Func factory) + public static void SetServerRegistrar(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the server registrar. /// - /// The composition. + /// The builder. /// A server registrar. - public static void SetServerRegistrar(this Composition composition, IServerRegistrar registrar) + public static void SetServerRegistrar(this IUmbracoBuilder builder, IServerRegistrar registrar) { - composition.Services.AddUnique(_ => registrar); + builder.Services.AddUnique(registrar); } /// /// Sets the server messenger. /// /// The type of the server registrar. - /// The composition. - public static void SetServerMessenger(this Composition composition) + /// The builder. + public static void SetServerMessenger(this IUmbracoBuilder builder) where T : class, IServerMessenger { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the server messenger. /// - /// The composition. + /// The builder. /// A function creating a server messenger. - public static void SetServerMessenger(this Composition composition, Func factory) + public static void SetServerMessenger(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the server messenger. /// - /// The composition. + /// The builder. /// A server messenger. - public static void SetServerMessenger(this Composition composition, IServerMessenger registrar) + public static void SetServerMessenger(this IUmbracoBuilder builder, IServerMessenger registrar) { - composition.Services.AddUnique(_ => registrar); + builder.Services.AddUnique(registrar); } /// /// Sets the database server messenger options. /// - /// The composition. + /// 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 Composition composition, Func factory) + public static void SetDatabaseServerMessengerCallbacks(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the database server messenger options. /// - /// The composition. + /// The builder. /// Options. /// Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default. - public static void SetDatabaseServerMessengerOptions(this Composition composition, DatabaseServerMessengerCallbacks options) + public static void SetDatabaseServerMessengerOptions(this IUmbracoBuilder builder, DatabaseServerMessengerCallbacks options) { - composition.Services.AddUnique(_ => options); + builder.Services.AddUnique(options); } /// /// Sets the short string helper. /// /// The type of the short string helper. - /// The composition. - public static void SetShortStringHelper(this Composition composition) + /// The builder. + public static void SetShortStringHelper(this IUmbracoBuilder builder) where T : class, IShortStringHelper { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the short string helper. /// - /// The composition. + /// The builder. /// A function creating a short string helper. - public static void SetShortStringHelper(this Composition composition, Func factory) + public static void SetShortStringHelper(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the short string helper. /// - /// A composition. + /// A builder. /// A short string helper. - public static void SetShortStringHelper(this Composition composition, IShortStringHelper helper) + public static void SetShortStringHelper(this IUmbracoBuilder builder, IShortStringHelper helper) { - composition.Services.AddUnique(_ => helper); + builder.Services.AddUnique(helper); } /// /// Sets the underlying media filesystem. /// - /// A composition. + /// A builder. /// A filesystem factory. /// /// Using this helper will ensure that your IFileSystem implementation is wrapped by the ShadowWrapper /// - public static void SetMediaFileSystem(this Composition composition, Func filesystemFactory) - => composition.Services.AddUnique(factory => + public static void SetMediaFileSystem(this IUmbracoBuilder builder, Func filesystemFactory) + => builder.Services.AddUnique(factory => { var fileSystems = factory.GetRequiredService(); return fileSystems.GetFileSystem(filesystemFactory(factory)); @@ -302,31 +303,31 @@ namespace Umbraco.Core /// Sets the log viewer. /// /// The type of the log viewer. - /// The composition. - public static void SetLogViewer(this Composition composition) + /// The builder. + public static void SetLogViewer(this IUmbracoBuilder builder) where T : class, ILogViewer { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } /// /// Sets the log viewer. /// - /// The composition. + /// The builder. /// A function creating a log viewer. - public static void SetLogViewer(this Composition composition, Func factory) + public static void SetLogViewer(this IUmbracoBuilder builder, Func factory) { - composition.Services.AddUnique(factory); + builder.Services.AddUnique(factory); } /// /// Sets the log viewer. /// - /// A composition. + /// A builder. /// A log viewer. - public static void SetLogViewer(this Composition composition, ILogViewer viewer) + public static void SetLogViewer(this IUmbracoBuilder builder, ILogViewer viewer) { - composition.Services.AddUnique(_ => viewer); + builder.Services.AddUnique(viewer); } #endregion diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs index 59c9b47400..c7f222f0ca 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogComposer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Logging.Serilog.Enrichers; using Umbraco.Infrastructure.Logging.Serilog.Enrichers; @@ -10,12 +11,12 @@ namespace Umbraco.Infrastructure.Logging.Serilog { public class SerilogComposer : ICoreComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + 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 e65e05de0f..856b6e892d 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Core.Logging.Viewer @@ -8,11 +9,11 @@ namespace Umbraco.Core.Logging.Viewer // ReSharper disable once UnusedMember.Global public class LogViewerComposer : ICoreComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Services.AddUnique(); - composition.SetLogViewer(); - composition.Services.AddUnique(factory => + builder.Services.AddUnique(); + builder.SetLogViewer(); + builder.Services.AddUnique(factory => { return new SerilogJsonLogViewer(factory.GetRequiredService>(), diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs index 19e0845703..08c890e5b0 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs @@ -1,15 +1,16 @@ -using Umbraco.Core.Composing; +using Umbraco.Core.Builder; +using Umbraco.Core.Composing; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes { public class PreValueMigratorComposer : ICoreComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { // do NOT add DefaultPreValueMigrator to this list! // it will be automatically used if nothing matches - composition.WithCollectionBuilder() + builder.WithCollectionBuilder() .Append() .Append() .Append() diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 65933399a3..7b98bd150e 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence /// // TODO: these comments are not true anymore // TODO: this class needs not be disposable! - internal class UmbracoDatabaseFactory : DisposableObjectSlim, IUmbracoDatabaseFactory + public class UmbracoDatabaseFactory : DisposableObjectSlim, IUmbracoDatabaseFactory { private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly GlobalSettings _globalSettings; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs index c34ce59fe6..e6db6a4328 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Templates; @@ -28,7 +29,7 @@ namespace Umbraco.Web.PropertyEditors Group = Constants.PropertyEditors.Groups.RichContent)] public class GridPropertyEditor : DataEditor { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IIOHelper _ioHelper; private readonly HtmlImageSourceParser _imageSourceParser; private readonly RichTextEditorPastedImages _pastedImages; @@ -37,7 +38,7 @@ namespace Umbraco.Web.PropertyEditors public GridPropertyEditor( ILoggerFactory loggerFactory, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, @@ -49,7 +50,7 @@ namespace Umbraco.Web.PropertyEditors IImageUrlGenerator imageUrlGenerator) : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _ioHelper = ioHelper; _imageSourceParser = imageSourceParser; _pastedImages = pastedImages; @@ -63,13 +64,13 @@ namespace Umbraco.Web.PropertyEditors /// Overridden to ensure that the value is validated /// /// - protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator); + protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator); protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor(_ioHelper); internal class GridPropertyValueEditor : DataValueEditor, IDataValueReference { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly HtmlImageSourceParser _imageSourceParser; private readonly RichTextEditorPastedImages _pastedImages; private readonly RichTextPropertyEditor.RichTextPropertyValueEditor _richTextPropertyValueEditor; @@ -78,7 +79,7 @@ namespace Umbraco.Web.PropertyEditors public GridPropertyValueEditor( DataEditorAttribute attribute, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, @@ -89,10 +90,10 @@ namespace Umbraco.Web.PropertyEditors IImageUrlGenerator imageUrlGenerator) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; _pastedImages = pastedImages; - _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages, imageUrlGenerator); + _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, backOfficeSecurityAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages, imageUrlGenerator); _mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute); _imageUrlGenerator = imageUrlGenerator; } @@ -121,7 +122,7 @@ namespace Umbraco.Web.PropertyEditors var grid = DeserializeGridValue(rawJson, out var rtes, out _); - var userId = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser?.Id ?? Constants.Security.SuperUserId; + var userId = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser?.Id ?? Constants.Security.SuperUserId; // Process the rte values foreach (var rte in rtes) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs deleted file mode 100644 index 2942271acc..0000000000 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; -using Umbraco.Core; - -namespace Umbraco.Web.PropertyEditors -{ - /// - /// Represents the 'startNode' value for the - /// - [JsonObject] - public class MultiNodePickerConfigurationTreeSource - { - [JsonProperty("type")] - public string ObjectType {get;set;} - - [JsonProperty("query")] - public string StartNodeQuery {get;set;} - - [JsonProperty("id")] - public Udi StartNodeId {get;set;} - } -} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index bf867ce648..049f020db4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Examine; @@ -28,7 +29,7 @@ namespace Umbraco.Web.PropertyEditors Icon = "icon-browser-window")] public class RichTextPropertyEditor : DataEditor { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly HtmlImageSourceParser _imageSourceParser; private readonly HtmlLocalLinkParser _localLinkParser; private readonly RichTextEditorPastedImages _pastedImages; @@ -40,7 +41,7 @@ namespace Umbraco.Web.PropertyEditors /// public RichTextPropertyEditor( ILoggerFactory loggerFactory, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, HtmlImageSourceParser imageSourceParser, @@ -52,7 +53,7 @@ namespace Umbraco.Web.PropertyEditors IImageUrlGenerator imageUrlGenerator) : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; _localLinkParser = localLinkParser; _pastedImages = pastedImages; @@ -64,7 +65,7 @@ namespace Umbraco.Web.PropertyEditors /// Create a custom value editor /// /// - protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator); + protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _backOfficeSecurityAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator); protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor(_ioHelper); @@ -75,7 +76,7 @@ namespace Umbraco.Web.PropertyEditors /// internal class RichTextPropertyValueEditor : DataValueEditor, IDataValueReference { - private IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly HtmlImageSourceParser _imageSourceParser; private readonly HtmlLocalLinkParser _localLinkParser; private readonly RichTextEditorPastedImages _pastedImages; @@ -83,7 +84,7 @@ namespace Umbraco.Web.PropertyEditors public RichTextPropertyValueEditor( DataEditorAttribute attribute, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, @@ -94,7 +95,7 @@ namespace Umbraco.Web.PropertyEditors IImageUrlGenerator imageUrlGenerator) : base(dataTypeService, localizationService,localizedTextService, shortStringHelper, attribute) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _imageSourceParser = imageSourceParser; _localLinkParser = localLinkParser; _pastedImages = pastedImages; @@ -146,7 +147,7 @@ namespace Umbraco.Web.PropertyEditors if (editorValue.Value == null) return null; - var userId = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser?.Id ?? Constants.Security.SuperUserId; + var userId = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser?.Id ?? Constants.Security.SuperUserId; var config = editorValue.DataTypeConfiguration as RichTextConfiguration; var mediaParent = config?.MediaParentId; diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index 0bf153dff5..b710594689 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -59,6 +59,7 @@ using Umbraco.Web.Trees; using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; using Microsoft.Extensions.Logging; +using Umbraco.Core.Builder; using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.HealthCheck; using Umbraco.Core.HealthCheck.Checks; @@ -69,12 +70,12 @@ namespace Umbraco.Core.Runtime [ComposeBefore(typeof(ICoreComposer))] public class CoreInitialComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); // composers - composition + builder .ComposeRepositories() .ComposeServices() .ComposeCoreMappingProfiles() @@ -83,27 +84,27 @@ namespace Umbraco.Core.Runtime // 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 - composition.Mappers().AddCoreMappers(); + builder.Mappers().AddCoreMappers(); // register the scope provider - composition.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor - composition.Services.AddUnique(f => f.GetRequiredService()); - composition.Services.AddUnique(f => f.GetRequiredService()); + builder.Services.AddUnique(); // implements both IScopeProvider and IScopeAccessor + builder.Services.AddUnique(f => f.GetRequiredService()); + builder.Services.AddUnique(f => f.GetRequiredService()); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + 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 - composition.Services.AddTransient(); + builder.Services.AddTransient(); // register manifest parser, will be injected in collection builders where needed - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register our predefined validators - composition.ManifestValueValidators() + builder.ManifestValueValidators() .Add() .Add() .Add() @@ -112,25 +113,25 @@ namespace Umbraco.Core.Runtime .Add(); // register the manifest filter collection builder (collection is empty by default) - composition.ManifestFilters(); + builder.ManifestFilters(); // properties and parameters derive from data editors - composition.DataEditors() - .Add(() => composition.TypeLoader.GetDataEditors()); + builder.DataEditors() + .Add(() => builder.TypeLoader.GetDataEditors()); - composition.MediaUrlGenerators() + builder.MediaUrlGenerators() .Add() .Add(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); // Used to determine if a datatype/editor should be storing/tracking // references to media item/s - composition.DataValueReferenceFactories(); + builder.DataValueReferenceFactories(); // register a server registrar, by default it's the db registrar - composition.Services.AddUnique(f => + builder.Services.AddUnique(f => { var globalSettings = f.GetRequiredService>().Value; @@ -146,7 +147,7 @@ namespace Umbraco.Core.Runtime // 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 - composition.Services.AddUnique(factory + builder.Services.AddUnique(factory => new DatabaseServerMessenger( factory.GetRequiredService(), factory.GetRequiredService(), @@ -161,107 +162,107 @@ namespace Umbraco.Core.Runtime factory.GetRequiredService>() )); - composition.CacheRefreshers() - .Add(() => composition.TypeLoader.GetCacheRefreshers()); + builder.CacheRefreshers() + .Add(() => builder.TypeLoader.GetCacheRefreshers()); - composition.PackageActions() - .Add(() => composition.TypeLoader.GetPackageActions()); + builder.PackageActions() + .Add(() => builder.TypeLoader.GetPackageActions()); - composition.PropertyValueConverters() - .Append(composition.TypeLoader.GetTypes()); + builder.PropertyValueConverters() + .Append(builder.TypeLoader.GetTypes()); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(factory + builder.Services.AddUnique(factory => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetRequiredService>().Value))); - composition.UrlSegmentProviders() + builder.UrlSegmentProviders() .Append(); - composition.Services.AddUnique(factory => new MigrationBuilder(factory)); + builder.Services.AddUnique(factory => new MigrationBuilder(factory)); // by default, register a noop factory - composition.Services.AddUnique(); + builder.Services.AddUnique(); // by default - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.SetCultureDictionaryFactory(); - composition.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); - composition.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 - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards - composition.Dashboards() - .Add(composition.TypeLoader.GetTypes()); + builder.Dashboards() + .Add(builder.TypeLoader.GetTypes()); // will be injected in controllers when needed to invoke rest endpoints on Our - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); // Grid config is not a real config file as we know them - composition.Services.AddUnique(); + builder.Services.AddUnique(); // Config manipulator - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register the umbraco context factory // composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.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 - composition.PropertyValueConverters() + builder.PropertyValueConverters() .Remove() .Remove() .Remove(); - composition.UrlProviders() + builder.UrlProviders() .Append() .Append(); - composition.MediaUrlProviders() + builder.MediaUrlProviders() .Append(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register properties fallback - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Actions() - .Add(() => composition.TypeLoader.GetTypes()); + builder.Actions() + .Add(() => builder.TypeLoader.GetTypes()); - composition.EditorValidators() - .Add(() => composition.TypeLoader.GetTypes()); + builder.EditorValidators() + .Add(() => builder.TypeLoader.GetTypes()); - composition.TourFilters(); + builder.TourFilters(); // replace with web implementation - composition.Services.AddUnique(); + 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 - composition.OEmbedProviders() + builder.OEmbedProviders() .Append() .Append() .Append() @@ -278,7 +279,7 @@ namespace Umbraco.Core.Runtime .Append(); // register back office sections in the order we want them rendered - composition.Sections() + builder.Sections() .Append() .Append() .Append() @@ -289,7 +290,7 @@ namespace Umbraco.Core.Runtime .Append(); // register known content apps - composition.ContentApps() + builder.ContentApps() .Append() .Append() .Append() @@ -299,18 +300,18 @@ namespace Umbraco.Core.Runtime .Append(); // register published router - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register *all* checks, except those marked [HideFromTypeFinder] of course - composition.HealthChecks() - .Add(() => composition.TypeLoader.GetTypes()); + builder.HealthChecks() + .Add(() => builder.TypeLoader.GetTypes()); - composition.WithCollectionBuilder() - .Add(() => composition.TypeLoader.GetTypes()); + builder.WithCollectionBuilder() + .Add(() => builder.TypeLoader.GetTypes()); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.ContentFinders() + builder.ContentFinders() // all built-in finders in the correct order, // devs can then modify this list on application startup .Append() @@ -320,61 +321,61 @@ namespace Umbraco.Core.Runtime .Append() .Append(); - composition.Services.AddScoped(); + builder.Services.AddScoped(); - composition.SearchableTrees() - .Add(() => composition.TypeLoader.GetTypes()); + builder.SearchableTrees() + .Add(() => builder.TypeLoader.GetTypes()); // replace some services - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register distributed cache - composition.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); + builder.Services.AddUnique(f => new DistributedCache(f.GetRequiredService(), f.GetRequiredService())); - composition.Services.AddScoped(); + builder.Services.AddScoped(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddScoped(factory => + builder.Services.AddUnique(); + builder.Services.AddScoped(factory => { var umbCtx = factory.GetRequiredService(); return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetRequiredService(), factory.GetRequiredService()); }); - composition.Services.AddUnique(); + 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. - composition.Services.AddUnique(); + builder.Services.AddUnique(); // register accessors for cultures - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddSingleton(); + builder.Services.AddSingleton(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); // Register noop versions for examine to be overridden by examine - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index a0c1718c07..cb02a90ebe 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -1,51 +1,67 @@ using System; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; -namespace Umbraco.Core.Runtime +namespace Umbraco.Infrastructure.Runtime { public class CoreRuntime : IRuntime { public IRuntimeState State { get; } + private readonly ILogger _logger; private readonly ComponentCollection _components; - private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker; private readonly IApplicationShutdownRegistry _applicationShutdownRegistry; private readonly IProfilingLogger _profilingLogger; private readonly IMainDom _mainDom; + private readonly IUmbracoDatabaseFactory _databaseFactory; public CoreRuntime( + ILogger logger, IRuntimeState state, ComponentCollection components, - IUmbracoBootPermissionChecker umbracoBootPermissionChecker, IApplicationShutdownRegistry applicationShutdownRegistry, IProfilingLogger profilingLogger, - IMainDom mainDom) + IMainDom mainDom, + IUmbracoDatabaseFactory databaseFactory) { State = state; + _logger = logger; _components = components; - _umbracoBootPermissionChecker = umbracoBootPermissionChecker; _applicationShutdownRegistry = applicationShutdownRegistry; _profilingLogger = profilingLogger; _mainDom = mainDom; + _databaseFactory = databaseFactory; } public void Start() { + AppDomain.CurrentDomain.UnhandledException += (_, args) => + { + var exception = (Exception)args.ExceptionObject; + var isTerminating = args.IsTerminating; // always true? + + var msg = "Unhandled exception in AppDomain"; + if (isTerminating) msg += " (terminating)"; + msg += "."; + _logger.LogError(exception, msg); + }; + + DetermineRuntimeLevel(); + if (State.Level <= RuntimeLevel.BootFailed) throw new InvalidOperationException($"Cannot start the runtime if the runtime level is less than or equal to {RuntimeLevel.BootFailed}"); - // throws if not full-trust - _umbracoBootPermissionChecker.ThrowIfNotPermissions(); - var hostingEnvironmentLifetime = _applicationShutdownRegistry; if (hostingEnvironmentLifetime == null) throw new InvalidOperationException($"An instance of {typeof(IApplicationShutdownRegistry)} could not be resolved from the container, ensure that one if registered in your runtime before calling {nameof(IRuntime)}.{nameof(Start)}"); // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate - AcquireMainDom(_mainDom, _applicationShutdownRegistry); + AcquireMainDom(); // create & initialize the components _components.Initialize(); @@ -53,16 +69,16 @@ namespace Umbraco.Core.Runtime public void Terminate() { - _components?.Terminate(); + _components.Terminate(); } - private void AcquireMainDom(IMainDom mainDom, IApplicationShutdownRegistry applicationShutdownRegistry) + private void AcquireMainDom() { using (var timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.")) { try { - mainDom.Acquire(applicationShutdownRegistry); + _mainDom.Acquire(_applicationShutdownRegistry); } catch { @@ -71,5 +87,29 @@ namespace Umbraco.Core.Runtime } } } + + private void DetermineRuntimeLevel() + { + using var timer = _profilingLogger.DebugDuration("Determining runtime level.", "Determined."); + + try + { + State.DetermineRuntimeLevel(); + + _logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", State.Level, State.Reason); + + if (State.Level == RuntimeLevel.Upgrade) + { + _logger.LogDebug("Configure database factory for upgrades."); + _databaseFactory.ConfigureForUpgrade(); + } + } + catch + { + State.Configure(RuntimeLevel.BootFailed, RuntimeLevelReason.BootFailedOnException); + timer?.Fail(); + throw; + } + } } } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntimeBootstrapper.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntimeBootstrapper.cs deleted file mode 100644 index 9b576324bd..0000000000 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntimeBootstrapper.cs +++ /dev/null @@ -1,376 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Events; -using Umbraco.Core.Exceptions; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Mappers; - -namespace Umbraco.Core.Runtime -{ - /// - /// Bootstraps the Core Umbraco runtime. - /// - /// Does not handle any of the web-related aspects of Umbraco (startup, etc). It - /// should be possible to use this runtime in console apps. - public class CoreRuntimeBootstrapper - { - // runtime state, this instance will get replaced again once the essential services are available to run the check - private RuntimeState _state = RuntimeState.Booting(); - private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker; - private readonly GlobalSettings _globalSettings; - private readonly ConnectionStrings _connectionStrings; - - public CoreRuntimeBootstrapper( - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, - IIOHelper ioHelper, - ILoggerFactory loggerFactory, - IProfiler profiler, - IUmbracoBootPermissionChecker umbracoBootPermissionChecker, - IHostingEnvironment hostingEnvironment, - IBackOfficeInfo backOfficeInfo, - IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom, - ITypeFinder typeFinder, - AppCaches appCaches) - { - _globalSettings = globalSettings; - _connectionStrings = connectionStrings; - - IOHelper = ioHelper; - AppCaches = appCaches; - UmbracoVersion = umbracoVersion; - Profiler = profiler; - HostingEnvironment = hostingEnvironment; - BackOfficeInfo = backOfficeInfo; - DbProviderFactoryCreator = dbProviderFactoryCreator; - - RuntimeLoggerFactory = loggerFactory; - _umbracoBootPermissionChecker = umbracoBootPermissionChecker; - - Logger = loggerFactory.CreateLogger(); - MainDom = mainDom; - TypeFinder = typeFinder; - } - - /// - /// Gets the logger. - /// - private ILogger Logger { get; } - - public ILoggerFactory RuntimeLoggerFactory { get; } - - protected IBackOfficeInfo BackOfficeInfo { get; } - - public IDbProviderFactoryCreator DbProviderFactoryCreator { get; } - - /// - /// Gets the profiler. - /// - protected IProfiler Profiler { get; } - - /// - /// Gets the profiling logger. - /// - public IProfilingLogger ProfilingLogger { get; private set; } - - /// - /// Gets the - /// - protected ITypeFinder TypeFinder { get; } - - /// - /// Gets the - /// - protected IIOHelper IOHelper { get; } - - protected IHostingEnvironment HostingEnvironment { get; } - public AppCaches AppCaches { get; } - public IUmbracoVersion UmbracoVersion { get; } - - /// - public IRuntimeState State => _state; - - public IMainDom MainDom { get; } - - /// - public virtual void Configure(IServiceCollection services) - { - if (services is null) throw new ArgumentNullException(nameof(services)); - - - // create and register the essential services - // ie the bare minimum required to boot - - // the boot loader boots using a container scope, so anything that is PerScope will - // be disposed after the boot loader has booted, and anything else will remain. - // note that this REQUIRES that perWebRequestScope has NOT been enabled yet, else - // the container will fail to create a scope since there is no http context when - // the application starts. - // the boot loader is kept in the runtime for as long as Umbraco runs, and components - // are NOT disposed - which is not a big deal as long as they remain lightweight - // objects. - - var umbracoVersion = new UmbracoVersion(); - var profilingLogger = ProfilingLogger = new ProfilingLogger(Logger, Profiler); - using (var timer = profilingLogger.TraceDuration( - $"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.", - "Booted.", - "Boot failed.")) - { - - Logger.LogInformation("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.", - HostingEnvironment?.SiteName, - HostingEnvironment?.ApplicationId, - HostingEnvironment?.ApplicationPhysicalPath, - NetworkHelper.MachineName); - Logger.LogDebug("Runtime: {Runtime}", GetType().FullName); - - AppDomain.CurrentDomain.SetData("DataDirectory", HostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); - - // application environment - ConfigureUnhandledException(); - Configure(services, timer); - } - } - - /// - /// Configure the runtime within a timer. - /// - private void Configure(IServiceCollection services, DisposableTimer timer) - { - if (services is null) throw new ArgumentNullException(nameof(services)); - if (timer is null) throw new ArgumentNullException(nameof(timer)); - - Composition composition = null; - - try - { - // run handlers - OnRuntimeBoot(); - - // type finder/loader - var typeLoader = new TypeLoader(TypeFinder, AppCaches.RuntimeCache, - new DirectoryInfo(HostingEnvironment.LocalTempPath), - RuntimeLoggerFactory.CreateLogger(), ProfilingLogger); - - services.AddUnique(Logger); - services.AddUnique(RuntimeLoggerFactory); - services.AddUnique(_umbracoBootPermissionChecker); - services.AddUnique(Profiler); - services.AddUnique(ProfilingLogger); - services.AddUnique(MainDom); - services.AddUnique(AppCaches); - services.AddUnique(AppCaches.RequestCache); - services.AddUnique(typeLoader); - services.AddUnique(TypeFinder); - services.AddUnique(IOHelper); - services.AddUnique(UmbracoVersion); - services.AddUnique(DbProviderFactoryCreator); - services.AddUnique(HostingEnvironment); - services.AddUnique(BackOfficeInfo); - services.AddUnique(); - - // NOTE: This instance of IUmbracoDatabaseFactory is only used to determine runtime state. - var bootstrapDatabaseFactory = CreateBootstrapDatabaseFactory(); - - // after bootstrapping we let the container wire up for us. - services.AddUnique(); - services.AddUnique(factory => factory.GetRequiredService().SqlContext); - services.AddUnique(factory => factory.GetRequiredService().BulkSqlInsertProvider); - - // re-create the state object with the essential services - _state = new RuntimeState(_globalSettings, UmbracoVersion, bootstrapDatabaseFactory, RuntimeLoggerFactory.CreateLogger()); - services.AddUnique(_state); - - - // create the composition - composition = new Composition(services, typeLoader, ProfilingLogger, _state, IOHelper, AppCaches); - - // run handlers - OnRuntimeEssentials(composition, AppCaches, typeLoader, bootstrapDatabaseFactory); - - try - { - // determine our runtime level - DetermineRuntimeLevel(bootstrapDatabaseFactory); - } - finally - { - // always run composers - RunComposers(typeLoader, composition); - } - - } - catch (Exception e) - { - var bfe = e as BootFailedException ?? new BootFailedException("Boot failed.", e); - - if (_state != null) - { - _state.Level = RuntimeLevel.BootFailed; - _state.BootFailedException = bfe; - } - - timer?.Fail(exception: bfe); // be sure to log the exception - even if we repeat ourselves - - Debugger.Break(); - - // throwing here can cause w3wp to hard-crash and we want to avoid it. - // instead, we're logging the exception and setting level to BootFailed. - // various parts of Umbraco such as UmbracoModule and UmbracoDefaultOwinStartup - // understand this and will nullify themselves, while UmbracoModule will - // throw a BootFailedException for every requests. - } - finally - { - composition?.RegisterBuilders(); - } - } - - protected virtual void ConfigureUnhandledException() - { - //take care of unhandled exceptions - there is nothing we can do to - // prevent the launch process to go down but at least we can try - // and log the exception - AppDomain.CurrentDomain.UnhandledException += (_, args) => - { - var exception = (Exception)args.ExceptionObject; - var isTerminating = args.IsTerminating; // always true? - - var msg = "Unhandled exception in AppDomain"; - if (isTerminating) msg += " (terminating)"; - msg += "."; - Logger.LogError(exception, msg); - }; - } - - private void RunComposers(TypeLoader typeLoader, Composition composition) - { - // get composers, and compose - var composerTypes = ResolveComposerTypes(typeLoader); - - IEnumerable enableDisableAttributes; - using (ProfilingLogger.DebugDuration("Scanning enable/disable composer attributes")) - { - enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); - } - - var composers = new Composers(composition, composerTypes, enableDisableAttributes, RuntimeLoggerFactory.CreateLogger(), ProfilingLogger); - composers.Compose(); - } - - - private void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory) - { - using var timer = ProfilingLogger.DebugDuration("Determining runtime level.", "Determined."); - - try - { - _state.DetermineRuntimeLevel(); - - Logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason); - - if (_state.Level == RuntimeLevel.Upgrade) - { - Logger.LogDebug("Configure database factory for upgrades."); - databaseFactory.ConfigureForUpgrade(); - } - } - catch - { - _state.Level = RuntimeLevel.BootFailed; - _state.Reason = RuntimeLevelReason.BootFailedOnException; - timer?.Fail(); - throw; - } - } - - private IEnumerable ResolveComposerTypes(TypeLoader typeLoader) - { - using (var timer = ProfilingLogger.TraceDuration("Resolving composer types.", "Resolved.")) - { - try - { - return GetComposerTypes(typeLoader); - } - catch - { - timer?.Fail(); - throw; - } - } - } - - #region Getters - - // getters can be implemented by runtimes inheriting from CoreRuntime - - /// - /// Gets all composer types. - /// - protected virtual IEnumerable GetComposerTypes(TypeLoader typeLoader) - => typeLoader.GetTypes(); - - /// - /// Returns the application path of the site/solution - /// - /// - /// - /// By default is null which means it's not running in any virtual folder. If the site is running in a virtual folder, this - /// can be overridden and the virtual path returned (i.e. /mysite/) - /// - protected virtual string GetApplicationRootPath() - => null; - - /// - /// Creates the database factory. - /// - /// This is strictly internal, for tests only. - protected internal virtual IUmbracoDatabaseFactory CreateBootstrapDatabaseFactory() - => new UmbracoDatabaseFactory( - RuntimeLoggerFactory.CreateLogger(), - RuntimeLoggerFactory, - Options.Create(_globalSettings), - Options.Create(_connectionStrings), - new Lazy(() => new MapperCollection(Enumerable.Empty())), - DbProviderFactoryCreator); - - - #endregion - - #region Events - - protected void OnRuntimeBoot() - { - RuntimeOptions.DoRuntimeBoot(ProfilingLogger); - RuntimeBooting?.Invoke(this, ProfilingLogger); - } - - protected void OnRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) - { - RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); - RuntimeEssentials?.Invoke(this, new RuntimeEssentialsEventArgs(composition, appCaches, typeLoader, databaseFactory)); - } - - public event TypedEventHandler RuntimeBooting; - public event TypedEventHandler RuntimeEssentials; - - #endregion - - } -} diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs deleted file mode 100644 index 78d068cb9c..0000000000 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Persistence; - -namespace Umbraco.Core.Runtime -{ - public class RuntimeEssentialsEventArgs : EventArgs - { - public RuntimeEssentialsEventArgs(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) - { - Composition = composition; - AppCaches = appCaches; - TypeLoader = typeLoader; - DatabaseFactory = databaseFactory; - } - - public Composition Composition { get; } - public AppCaches AppCaches { get; } - public TypeLoader TypeLoader { get; } - public IUmbracoDatabaseFactory DatabaseFactory { get; } - } -} diff --git a/src/Umbraco.Infrastructure/RuntimeOptions.cs b/src/Umbraco.Infrastructure/RuntimeOptions.cs deleted file mode 100644 index 23abd474a4..0000000000 --- a/src/Umbraco.Infrastructure/RuntimeOptions.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; - -namespace Umbraco.Core -{ - /// - /// Provides static options for the runtime. - /// - /// - /// These options can be configured in PreApplicationStart or via appSettings. - /// - public static class RuntimeOptions - { - private static List> _onBoot; - private static List> _onEssentials; - - /// - /// Executes the RuntimeBoot handlers. - /// - internal static void DoRuntimeBoot(IProfilingLogger logger) - { - if (_onBoot == null) - return; - - foreach (var action in _onBoot) - action(logger); - } - - /// - /// Executes the RuntimeEssentials handlers. - /// - internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) - { - if (_onEssentials== null) - return; - - foreach (var action in _onEssentials) - action(composition, appCaches, typeLoader, databaseFactory); - } - - /// - /// Registers a RuntimeBoot handler. - /// - /// - /// A RuntimeBoot handler runs when the runtime boots, right after the - /// loggers have been created, but before anything else. - /// - public static void OnRuntimeBoot(Action action) - { - if (_onBoot == null) - _onBoot = new List>(); - _onBoot.Add(action); - } - - /// - /// Registers a RuntimeEssentials handler. - /// - /// - /// A RuntimeEssentials handler runs after the runtime has created a few - /// essential things (AppCaches, a TypeLoader, and a database factory) but - /// before anything else. - /// - public static void OnRuntimeEssentials(Action action) - { - if (_onEssentials == null) - _onEssentials = new List>(); - _onEssentials.Add(action); - } - } -} diff --git a/src/Umbraco.Infrastructure/RuntimeState.cs b/src/Umbraco.Infrastructure/RuntimeState.cs index cb2358d083..505cf045c3 100644 --- a/src/Umbraco.Infrastructure/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/RuntimeState.cs @@ -2,6 +2,7 @@ using System.Threading; using Semver; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; @@ -32,9 +33,9 @@ namespace Umbraco.Core /// /// Initializes a new instance of the class. /// - public RuntimeState(GlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoDatabaseFactory databaseFactory, ILogger logger) + public RuntimeState(IOptions globalSettings, IUmbracoVersion umbracoVersion, IUmbracoDatabaseFactory databaseFactory, ILogger logger) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _umbracoVersion = umbracoVersion; _databaseFactory = databaseFactory; _logger = logger; @@ -160,6 +161,12 @@ namespace Umbraco.Core Reason = RuntimeLevelReason.UpgradeMigrations; } + public void Configure(RuntimeLevel level, RuntimeLevelReason reason) + { + Level = level; + Reason = reason; + } + private bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); diff --git a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs index e8ee269aac..87deb21bde 100644 --- a/src/Umbraco.Infrastructure/Search/ExamineComposer.cs +++ b/src/Umbraco.Infrastructure/Search/ExamineComposer.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -16,21 +17,21 @@ namespace Umbraco.Web.Search /// public sealed class ExamineComposer : ComponentComposer, ICoreComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); // populators are not a collection: one cannot remove ours, and can only add more // the container can inject IEnumerable and get them all - composition.Services.AddSingleton(); - composition.Services.AddSingleton(); - composition.Services.AddSingleton(); - composition.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); - composition.Services.AddSingleton(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(factory => + builder.Services.AddSingleton(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => new ContentValueSetBuilder( factory.GetRequiredService(), factory.GetRequiredService(), @@ -38,7 +39,7 @@ namespace Umbraco.Web.Search factory.GetRequiredService(), factory.GetRequiredService(), true)); - composition.Services.AddUnique(factory => + builder.Services.AddUnique(factory => new ContentValueSetBuilder( factory.GetRequiredService(), factory.GetRequiredService(), @@ -46,9 +47,9 @@ namespace Umbraco.Web.Search factory.GetRequiredService(), factory.GetRequiredService(), false)); - composition.Services.AddUnique, MediaValueSetBuilder>(); - composition.Services.AddUnique, MemberValueSetBuilder>(); - composition.Services.AddUnique(); + builder.Services.AddUnique, MediaValueSetBuilder>(); + builder.Services.AddUnique, MemberValueSetBuilder>(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs index b907d07627..6a048daca4 100644 --- a/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs +++ b/src/Umbraco.Infrastructure/WebAssets/WebAssetsComposer.cs @@ -1,14 +1,15 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Web.WebAssets { public sealed class WebAssetsComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); - composition.Services.AddUnique(); + base.Compose(builder); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index aa8f91c508..324b5f0df7 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -7,23 +7,24 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.Builder; namespace Umbraco.ModelsBuilder.Embedded.Compose { [ComposeBefore(typeof(IPublishedCacheComposer))] public sealed class ModelsBuilderComposer : ICoreComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Components().Append(); - composition.Services.AddSingleton(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Components().Append(); + builder.Services.AddSingleton(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(factory => + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => { var config = factory.GetRequiredService>().Value; if (config.ModelsMode == ModelsMode.PureLive) diff --git a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs b/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs index ea8863dbd7..eb1b4b3d5f 100644 --- a/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs +++ b/src/Umbraco.PublishedCache.NuCache/NuCacheComposer.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.Scoping; @@ -11,21 +12,21 @@ namespace Umbraco.Web.PublishedCache.NuCache { public class NuCacheComposer : ComponentComposer, IPublishedCacheComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); // register the NuCache database data source - composition.Services.AddTransient(); + builder.Services.AddTransient(); // register the NuCache published snapshot service // must register default options, required in the service ctor - composition.Services.AddTransient(factory => new PublishedSnapshotServiceOptions()); - composition.SetPublishedSnapshotService(); + builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions()); + builder.SetPublishedSnapshotService(); // replace this service since we want to improve the content/media // mapping lookups if we are using nucache. - composition.Services.AddUnique(factory => + builder.Services.AddUnique(factory => { var idkSvc = new IdKeyMap(factory.GetRequiredService()); var publishedSnapshotService = factory.GetRequiredService() as PublishedSnapshotService; diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 688515ad33..2b80b32b71 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -3,19 +3,14 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using CSharpTest.Net.Collections; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.Install; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -30,8 +25,8 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Net; using Umbraco.Web.Cache; -using Umbraco.Web.Install; using Umbraco.Web.PublishedCache.NuCache.DataSource; using Umbraco.Web.Routing; using File = System.IO.File; @@ -40,6 +35,10 @@ namespace Umbraco.Web.PublishedCache.NuCache { internal class PublishedSnapshotService : PublishedSnapshotServiceBase { + private readonly PublishedSnapshotServiceOptions _options; + private readonly IMainDom _mainDom; + private readonly IUmbracoApplicationLifetime _lifeTime; + private readonly IRuntimeState _runtime; private readonly ServiceContext _serviceContext; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; private readonly IProfilingLogger _profilingLogger; @@ -63,9 +62,9 @@ namespace Umbraco.Web.PublishedCache.NuCache // volatile because we read it with no lock private volatile bool _isReady; - private readonly ContentStore _contentStore; - private readonly ContentStore _mediaStore; - private readonly SnapDictionary _domainStore; + private ContentStore _contentStore; + private ContentStore _mediaStore; + private SnapDictionary _domainStore; private readonly object _storesLock = new object(); private readonly object _elementsLock = new object(); @@ -84,13 +83,21 @@ namespace Umbraco.Web.PublishedCache.NuCache //private static int _singletonCheck; - public PublishedSnapshotService(PublishedSnapshotServiceOptions options, IMainDom mainDom, IRuntimeState runtime, - ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + public PublishedSnapshotService( + PublishedSnapshotServiceOptions options, + IMainDom mainDom, + IUmbracoApplicationLifetime lifeTime, + IRuntimeState runtime, + ServiceContext serviceContext, + IPublishedContentTypeFactory publishedContentTypeFactory, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory, IScopeProvider scopeProvider, - IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, + IDocumentRepository documentRepository, + IMediaRepository mediaRepository, + IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, IDataSource dataSource, IOptions globalSettings, @@ -106,6 +113,10 @@ namespace Umbraco.Web.PublishedCache.NuCache //if (Interlocked.Increment(ref _singletonCheck) > 1) // throw new Exception("Singleton must be instantiated only once!"); + _options = options; + _mainDom = mainDom; + _lifeTime = lifeTime; + _runtime = runtime; _serviceContext = serviceContext; _publishedContentTypeFactory = publishedContentTypeFactory; _profilingLogger = profilingLogger; @@ -134,12 +145,17 @@ namespace Umbraco.Web.PublishedCache.NuCache // (ideally we'd have Upgrading.App vs Upgrading.Data application states...) InitializeRepositoryEvents(); + _lifeTime.ApplicationInit += OnApplicationInit; + } + + internal void OnApplicationInit(object sender, EventArgs e) + { // however, the cache is NOT available until we are configured, because loading // content (and content types) from database cannot be consistent (see notes in "Handle // Notifications" region), so // - notifications will be ignored // - trying to obtain a published snapshot from the service will throw - if (runtime.Level != RuntimeLevel.Run) + if (_runtime.Level != RuntimeLevel.Run) return; // lock this entire call, we only want a single thread to be accessing the stores at once and within @@ -148,25 +164,25 @@ namespace Umbraco.Web.PublishedCache.NuCache // it will not be able to close the stores until we are done populating (if the store is empty) lock (_storesLock) { - if (options.IgnoreLocalDb == false) + if (!_options.IgnoreLocalDb) { - var registered = mainDom.Register(MainDomRegister, MainDomRelease); + _mainDom.Register(MainDomRegister, MainDomRelease); // stores are created with a db so they can write to it, but they do not read from it, // stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to // figure out whether it can read the databases or it should populate them from sql _logger.LogInformation("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists); - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory, _localContentDb); + _contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localContentDb); _logger.LogInformation("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory, _localMediaDb); + _mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory, _localMediaDb); } else { _logger.LogInformation("Creating the content store (local db ignored)"); - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory); + _contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); _logger.LogInformation("Creating the media store (local db ignored)"); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory); + _mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, _publishedModelFactory); } _domainStore = new SnapDictionary(); @@ -330,6 +346,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Dispose() { TearDownRepositoryEvents(); + _lifeTime.ApplicationInit -= OnApplicationInit; base.Dispose(); } diff --git a/src/Umbraco.TestData/LoadTestController.cs b/src/Umbraco.TestData/LoadTestController.cs index fbb031c6db..ed9e0b456e 100644 --- a/src/Umbraco.TestData/LoadTestController.cs +++ b/src/Umbraco.TestData/LoadTestController.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using Umbraco.Core.Composing; using System.Configuration; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Builder; using Umbraco.Core.Strings; // see https://github.com/Shazwazza/UmbracoScripts/tree/master/src/LoadTesting @@ -362,14 +363,14 @@ namespace Umbraco.TestData public class TestComposer : ComponentComposer, IUserComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); if (ConfigurationManager.AppSettings["Umbraco.TestData.Enabled"] != "true") return; - composition.Services.AddScoped(typeof(LoadTestController)); + builder.Services.AddScoped(typeof(LoadTestController)); } } } diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs index 7eafdc6271..fd9ffe5d26 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -66,7 +66,7 @@ namespace Umbraco.Tests.Integration.Implementations _hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of()); ConsoleLoggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); - ProfilingLogger = new ProfilingLogger(ConsoleLoggerFactory.CreateLogger("ProfilingLogger"), Profiler); + ProfilingLogger = new ProfilingLogger(ConsoleLoggerFactory.CreateLogger(), Profiler); } diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index eec62b9331..89006ef245 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; @@ -9,9 +10,11 @@ using Moq; using NUnit.Framework; using Microsoft.Extensions.Logging; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Runtime; @@ -20,6 +23,7 @@ using Umbraco.Tests.Common; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.Integration { @@ -41,68 +45,6 @@ namespace Umbraco.Tests.Integration MyComposer.Reset(); } - /// - /// Manually configure the containers/dependencies and call Boot on Core runtime - /// - [Test] - public void Boot_Core_Runtime() - { - var services = new ServiceCollection().AddLazySupport(); - - // Special case since we are not using the Generic Host, we need to manually add an AspNetCore service to the container - services.AddTransient(x => Mock.Of()); - - var testHelper = new TestHelper(); - - var globalSettings = new GlobalSettings(); - var connectionStrings = new ConnectionStrings(); - - // TODO: found these registration were necessary here (as we haven't called the HostBuilder?), as dependencies for ComponentCollection - // are not resolved. Need to check this if these explicit registrations are the best way to handle this. - - services.AddTransient(x => Options.Create(globalSettings)); - services.AddTransient(x => Options.Create(connectionStrings)); - services.AddTransient(x => Options.Create(new ContentSettings())); - services.AddTransient(x => Options.Create(new CoreDebugSettings())); - services.AddTransient(x => Options.Create(new NuCacheSettings())); - services.AddTransient(x => Options.Create(new RequestHandlerSettings())); - services.AddTransient(x => Options.Create(new UserPasswordConfigurationSettings())); - services.AddTransient(x => Options.Create(new WebRoutingSettings())); - services.AddTransient(x => Options.Create(new ModelsBuilderSettings())); - services.AddTransient(x => Options.Create(new RouteOptions())); - services.AddTransient(x => Options.Create(new IndexCreatorSettings())); - services.AddRouting(); // LinkGenerator - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - - // Create the core runtime - var bootstrapper = new CoreRuntimeBootstrapper(globalSettings, connectionStrings, testHelper.GetUmbracoVersion(), - testHelper.IOHelper, testHelper.ConsoleLoggerFactory, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, - testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, - testHelper.MainDom, testHelper.GetTypeFinder(), AppCaches.NoCache); - - bootstrapper.Configure(services); - - Assert.IsTrue(bootstrapper.MainDom.IsMainDom); - Assert.IsNull(bootstrapper.State.BootFailedException); - Assert.AreEqual(RuntimeLevel.Install, bootstrapper.State.Level); - Assert.IsTrue(MyComposer.IsComposed); - Assert.IsFalse(MyComponent.IsInit); - Assert.IsFalse(MyComponent.IsTerminated); - - var container = services.BuildServiceProvider(); - - var runtime = container.GetRequiredService(); - - runtime.Start(); - - Assert.IsTrue(MyComponent.IsInit); - Assert.IsFalse(MyComponent.IsTerminated); - - runtime.Terminate(); - - Assert.IsTrue(MyComponent.IsTerminated); - } - /// /// Calling AddUmbracoCore to configure the container /// @@ -120,8 +62,19 @@ namespace Umbraco.Tests.Integration services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); // Add it! - services.AddUmbracoConfiguration(hostContext.Configuration); - services.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration); + 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(); + builder.AddUmbracoCore(); }); var host = await hostBuilder.StartAsync(); @@ -133,7 +86,6 @@ namespace Umbraco.Tests.Integration Assert.IsFalse(mainDom.IsMainDom); // We haven't "Started" the runtime yet Assert.IsNull(runtimeState.BootFailedException); - Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); Assert.IsFalse(MyComponent.IsInit); // We haven't "Started" the runtime yet await host.StopAsync(); @@ -157,10 +109,23 @@ namespace Umbraco.Tests.Integration var webHostEnvironment = testHelper.GetWebHostEnvironment(); services.AddSingleton(testHelper.DbProviderFactoryCreator); services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); - + // Add it! - services.AddUmbracoConfiguration(hostContext.Configuration); - services.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(),hostContext.Configuration); + + 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() + .Build(); services.AddRouting(); // LinkGenerator }); @@ -177,7 +142,6 @@ namespace Umbraco.Tests.Integration Assert.IsTrue(mainDom.IsMainDom); Assert.IsNull(runtimeState.BootFailedException); - Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); Assert.IsTrue(MyComponent.IsInit); await host.StopAsync(); @@ -187,9 +151,9 @@ namespace Umbraco.Tests.Integration public class MyComposer : IUserComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Components().Append(); + builder.Components().Append(); IsComposed = true; } diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs index 171914ecd6..897bc38c2f 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -1,9 +1,10 @@ -using System; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; +using Umbraco.Core.Logging; using Umbraco.Core.Runtime; -using Umbraco.Extensions; using Umbraco.Tests.Integration.Implementations; -using Umbraco.Tests.Integration.Testing; using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.Integration.TestServerTest @@ -15,39 +16,15 @@ namespace Umbraco.Tests.Integration.TestServerTest /// /// /// - public static IUmbracoBuilder WithTestCore(this IUmbracoBuilder builder, TestHelper testHelper, - Action dbInstallEventHandler) + public static IUmbracoBuilder AddTestCore(this IUmbracoBuilder builder, TestHelper testHelper) { - return builder.AddWith(nameof(global::Umbraco.Web.Common.Builder.UmbracoBuilderExtensions.WithCore), - () => - { - builder.Services.AddUmbracoCore( - builder.WebHostEnvironment, - typeof(UmbracoBuilderExtensions).Assembly, - AppCaches.NoCache, // Disable caches in integration tests - testHelper.GetLoggingConfiguration(), - builder.Config, - // TODO: Yep that's extremely ugly - (globalSettings, connectionStrings, umbVersion, ioHelper, loggerFactory, profiler, hostingEnv, backOfficeInfo, typeFinder, appCaches, dbProviderFactoryCreator) => - { - var runtime = UmbracoIntegrationTest.CreateTestRuntime( - globalSettings, - connectionStrings, - umbVersion, - ioHelper, - loggerFactory, - profiler, - hostingEnv, - backOfficeInfo, - typeFinder, - appCaches, - dbProviderFactoryCreator, - testHelper.MainDom, // SimpleMainDom - dbInstallEventHandler); // DB Installation event handler + builder.AddUmbracoCore(); - return runtime; - }); - }); + 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 792b5cd5c1..f6ece372ea 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -21,6 +21,9 @@ using Umbraco.Web; using Umbraco.Web.Common.Builder; using Umbraco.Web.Common.Controllers; using Microsoft.Extensions.Hosting; +using Umbraco.Core.Cache; +using Umbraco.Core.Persistence; +using Umbraco.Core.Runtime; using Umbraco.Web.BackOffice.Controllers; namespace Umbraco.Tests.Integration.TestServerTest @@ -70,6 +73,7 @@ namespace Umbraco.Tests.Integration.TestServerTest // call startup builder.Configure(app => { + UseTestLocalDb(app.ApplicationServices); Services = app.ApplicationServices; Configure(app); }); @@ -126,21 +130,25 @@ namespace Umbraco.Tests.Integration.TestServerTest public override void ConfigureServices(IServiceCollection services) { - var umbracoBuilder = services.AddUmbraco(TestHelper.GetWebHostEnvironment(), Configuration); - umbracoBuilder - .WithConfiguration() - .WithTestCore(TestHelper, UseTestLocalDb) // This is the important one! - .WithWebComponents() - .WithRuntimeMinifier() - .WithBackOffice() - .WithBackOfficeIdentity() - .WithPreview() + var typeLoader = services.AddTypeLoader(GetType().Assembly, TestHelper.GetWebHostEnvironment(), TestHelper.GetHostingEnvironment(), + TestHelper.ConsoleLoggerFactory, AppCaches.NoCache, Configuration, TestHelper.Profiler); + + var builder = new UmbracoBuilder(services, Configuration, typeLoader); + + builder + .AddConfiguration() + .AddTestCore(TestHelper) // This is the important one! + .AddWebComponents() + .AddRuntimeMinifier() + .AddBackOffice() + .AddBackOfficeIdentity() + .AddPreviewSupport() //.WithMiniProfiler() // we don't want this running in tests - .WithMvcAndRazor(mvcBuilding: mvcBuilder => + .AddMvcAndRazor(mvcBuilding: mvcBuilder => { mvcBuilder.AddApplicationPart(typeof(ContentController).Assembly); }) - .WithWebServer() + .AddWebServer() .Build(); } diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs index a0a4f4f886..c556d4d29d 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; @@ -37,27 +38,25 @@ namespace Umbraco.Tests.Integration.Testing /// public class IntegrationTestComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.Components().Remove(); - composition.Services.AddUnique(); - composition.Services.AddUnique(factory => Mock.Of()); + builder.Components().Remove(); + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => Mock.Of()); // we don't want persisted nucache files in tests - composition.Services.AddTransient(factory => new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }); + builder.Services.AddTransient(factory => new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }); // ensure all lucene indexes are using RAM directory (no file system) - composition.Services.AddUnique(); + builder.Services.AddUnique(); // replace this service so that it can lookup the correct file locations - composition.Services.AddUnique(GetLocalizedTextService); - - composition.Services.AddUnique(); - composition.Services.AddUnique(); - + builder.Services.AddUnique(GetLocalizedTextService); + builder.Services.AddUnique(); + builder.Services.AddUnique(); } /// diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 1232fba287..db71603089 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -26,12 +26,15 @@ using System.Collections.Generic; using Microsoft.Extensions.Configuration; using System.Data.SqlClient; using System.Data.Common; +using System.Diagnostics; using System.IO; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Serilog; +using Umbraco.Core.Builder; +using Umbraco.Web.Common.Builder; using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; namespace Umbraco.Tests.Integration.Testing @@ -109,25 +112,27 @@ namespace Umbraco.Tests.Integration.Testing private ILoggerFactory CreateLoggerFactory() { - ILoggerFactory factory; - var testOptions = TestOptionAttributeBase.GetTestOptions(); - switch (testOptions.Logger) + try { - case UmbracoTestOptions.Logger.Mock: - factory = NullLoggerFactory.Instance; - break; - case UmbracoTestOptions.Logger.Serilog: - factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); - break; - case UmbracoTestOptions.Logger.Console: - factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); - break; - default: - throw new NotSupportedException($"Logger option {testOptions.Logger} is not supported."); + var testOptions = TestOptionAttributeBase.GetTestOptions(); + switch (testOptions.Logger) + { + case UmbracoTestOptions.Logger.Mock: + return NullLoggerFactory.Instance; + case UmbracoTestOptions.Logger.Serilog: + return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); + case UmbracoTestOptions.Logger.Console: + return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); + } + } + catch + { + // ignored } - return factory; + return NullLoggerFactory.Instance; } + /// /// Create the Generic Host and execute startup ConfigureServices/Configure calls /// @@ -156,95 +161,7 @@ namespace Umbraco.Tests.Integration.Testing }); return hostBuilder; } - - /// - /// Creates a instance for testing and registers an event handler for database install - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public CoreRuntimeBootstrapper CreateTestRuntime( - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, IIOHelper ioHelper, - ILoggerFactory loggerFactory, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, - ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator) - { - var runtime = CreateTestRuntime( - globalSettings, - connectionStrings, - umbracoVersion, - ioHelper, - loggerFactory, - profiler, - hostingEnvironment, - backOfficeInfo, - typeFinder, - appCaches, - dbProviderFactoryCreator, - TestHelper.MainDom, // SimpleMainDom - UseTestLocalDb // DB Installation event handler - ); - - return runtime; - } - - /// - /// Creates a instance for testing and registers an event handler for database install - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// The event handler used for DB installation - /// - /// - public static CoreRuntimeBootstrapper CreateTestRuntime( - GlobalSettings globalSettings, - ConnectionStrings connectionStrings, - IUmbracoVersion umbracoVersion, IIOHelper ioHelper, - ILoggerFactory loggerFactory, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, - ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator, - IMainDom mainDom, Action eventHandler) - { - var runtime = new CoreRuntimeBootstrapper( - globalSettings, - connectionStrings, - umbracoVersion, - ioHelper, - loggerFactory, - profiler, - Mock.Of(), - hostingEnvironment, - backOfficeInfo, - dbProviderFactoryCreator, - mainDom, - typeFinder, - appCaches); - - runtime.RuntimeEssentials += (sender, args) => eventHandler(sender, args); - - return runtime; - } - + #endregion #region IStartup @@ -256,25 +173,38 @@ namespace Umbraco.Tests.Integration.Testing services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment); // Add it! - services.AddUmbracoConfiguration(Configuration); - services.AddUmbracoCore( - webHostEnvironment, + var typeLoader = services.AddTypeLoader( GetType().Assembly, - GetAppCaches(), - TestHelper.GetLoggingConfiguration(), + webHostEnvironment, + TestHelper.GetHostingEnvironment(), + TestHelper.ConsoleLoggerFactory, + AppCaches.NoCache, Configuration, - CreateTestRuntime); + TestHelper.Profiler); + var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory); + + + builder.Services.AddLogger(TestHelper.GetHostingEnvironment(), TestHelper.GetLoggingConfiguration(), Configuration); + + builder.AddConfiguration() + .AddUmbracoCore(); + + builder.Services.AddUnique(GetAppCaches()); + builder.Services.AddUnique(Mock.Of()); + builder.Services.AddUnique(TestHelper.MainDom); services.AddSignalR(); - services.AddUmbracoWebComponents(Configuration); - services.AddUmbracoRuntimeMinifier(Configuration); - services.AddUmbracoBackOffice(); + builder.AddWebComponents(); + builder.AddRuntimeMinifier(); + builder.AddBackOffice(); services.AddUmbracoBackOfficeIdentity(); services.AddMvc(); + builder.Build(); + CustomTestSetup(services); } @@ -286,6 +216,8 @@ namespace Umbraco.Tests.Integration.Testing public virtual void Configure(IApplicationBuilder app) { + UseTestLocalDb(app.ApplicationServices); + //get the currently set options var testOptions = TestOptionAttributeBase.GetTestOptions(); if (testOptions.Boot) @@ -306,6 +238,7 @@ namespace Umbraco.Tests.Integration.Testing protected void TerminateCoreRuntime() { Services.GetRequiredService().Terminate(); + StaticApplicationLogging.Initialize(null); } #endregion @@ -315,24 +248,15 @@ namespace Umbraco.Tests.Integration.Testing private static readonly object _dbLocker = new object(); private static LocalDbTestDatabase _dbInstance; - /// - /// Event handler for the to install the database - /// - /// - /// - protected void UseTestLocalDb(CoreRuntimeBootstrapper runtimeBootstrapper, RuntimeEssentialsEventArgs args) + protected void UseTestLocalDb(IServiceProvider serviceProvider) { - // This will create a db, install the schema and ensure the app is configured to run - InstallTestLocalDb(args.DatabaseFactory, runtimeBootstrapper.RuntimeLoggerFactory, runtimeBootstrapper.State, TestHelper.WorkingDirectory); - TestDBConnectionString = args.DatabaseFactory.ConnectionString; - InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString; + var state = serviceProvider.GetRequiredService(); + var databaseFactory = serviceProvider.GetRequiredService(); - // Re-configure IOptions now that we have a test db - // This is what will be resolved first time IUmbracoDatabaseFactory is resolved from container (e.g. post CoreRuntime bootstrap) - args.Composition.Services.Configure((x) => - { - x.UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, TestDBConnectionString); - }); + // This will create a db, install the schema and ensure the app is configured to run + InstallTestLocalDb(databaseFactory, TestHelper.ConsoleLoggerFactory, state, TestHelper.WorkingDirectory); + TestDBConnectionString = databaseFactory.ConnectionString; + InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString; } /// diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs index 511d20588f..56bacb93a9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs @@ -8,21 +8,18 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Boot = true)] public class RelationRepositoryTest : UmbracoIntegrationTest { private RelationType _relateContent; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs index 2976aca085..5542f926e1 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopedRepositoryTests.cs @@ -44,6 +44,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Scoping return result; } + [TearDown] public void Teardown() { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs index ecb3292727..b7ab3ceea1 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs @@ -9,10 +9,12 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Net; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.PublishedCache; +using Umbraco.Web.PublishedCache.NuCache; namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { @@ -42,7 +44,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { //This is super nasty, but this lets us initialize the cache while it is empty. - _ = GetRequiredService(); + var publishedSnapshotService = GetRequiredService() as PublishedSnapshotService; + publishedSnapshotService?.OnApplicationInit(null, EventArgs.Empty); if (_langFr == null && _langEs == null) { diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs index bf3f14004a..4093dfb892 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/BaseUsingSqlSyntax.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NPoco; @@ -11,6 +12,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Tests.UnitTests.TestHelpers; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.TestHelpers { @@ -32,7 +34,8 @@ namespace Umbraco.Tests.TestHelpers var container = TestHelper.GetServiceCollection(); var typeLoader = TestHelper.GetMockedTypeLoader(); - var composition = new Composition(container, typeLoader, Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); + composition.WithCollectionBuilder() .AddCoreMappers(); diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs index 6a4f228070..7bbfed4e85 100644 --- a/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/CompositionExtensions.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Tests.UnitTests.TestHelpers @@ -7,10 +8,10 @@ namespace Umbraco.Tests.UnitTests.TestHelpers public static class CompositionExtensions { [Obsolete("This extension method exists only to ease migration, please refactor")] - public static IServiceProvider CreateServiceProvider(this Composition composition) + public static IServiceProvider CreateServiceProvider(this IUmbracoBuilder builder) { - composition.RegisterBuilders(); - return composition.Services.BuildServiceProvider(); + builder.Build(); + return builder.Services.BuildServiceProvider(); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index f9cfef38c3..4cc2a54327 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; @@ -9,6 +10,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; @@ -19,6 +21,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components { @@ -49,7 +52,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components mock.Setup(x => x.GetService(typeof (ILogger))).Returns(logger); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(loggerFactory.CreateLogger); mock.Setup(x => x.GetService(typeof(ILoggerFactory))).Returns(loggerFactory); - mock.Setup(x => x.GetService(typeof (IProfilingLogger))).Returns(new ProfilingLogger(logger, Mock.Of())); + mock.Setup(x => x.GetService(typeof (IProfilingLogger))).Returns(new ProfilingLogger(loggerFactory.CreateLogger(), Mock.Of())); mock.Setup(x => x.GetService(typeof (IUmbracoDatabaseFactory))).Returns(f); mock.Setup(x => x.GetService(typeof (IScopeProvider))).Returns(p); @@ -74,11 +77,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Boot1A() { var register = MockRegister(); - var typeLoader = MockTypeLoader(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User @@ -94,7 +96,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components if (type == typeof(Composer1)) return new Composer1(); if (type == typeof(Composer5)) return new Composer5(); if (type == typeof(Component5)) return new Component5(new SomeResource()); - if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of(), Mock.Of()); + if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of>(), Mock.Of()); if (type == typeof(ILogger)) return Mock.Of>(); throw new NotSupportedException(type.FullName); }); @@ -115,10 +117,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Boot1B() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(x=>x.Level == RuntimeLevel.Run), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User - stays with RuntimeLevel.Run @@ -131,10 +133,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Boot2() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); // 21 is required by 20 // => reorder components accordingly @@ -146,10 +148,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Boot3() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); // i23 requires 22 // 24, 25 implement i23 @@ -163,10 +165,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void BrokenRequire() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); try { @@ -186,10 +188,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void BrokenRequired() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); // 2 is Core and requires 4 // 13 is required by 1 @@ -218,15 +220,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components if (type == typeof(Composer5a)) return new Composer5a(); if (type == typeof(Component5)) return new Component5(new SomeResource()); if (type == typeof(Component5a)) return new Component5a(); - if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of(), Mock.Of()); + if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of>(), Mock.Of()); if (type == typeof(ILogger)) return Mock.Of>(); throw new NotSupportedException(type.FullName); }); }); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Assert.IsEmpty(Composed); composers.Compose(); @@ -249,10 +251,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Requires1() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); @@ -264,10 +266,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void Requires2A() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(3, Composed.Count); @@ -281,10 +283,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components var register = MockRegister(); var typeLoader = MockTypeLoader(); var factory = MockFactory(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(x=>x.Level == RuntimeLevel.Run), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); var builder = composition.WithCollectionBuilder(); @@ -300,35 +302,35 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void WeakDependencies() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer10) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(1, Composed.Count); Assert.AreEqual(typeof(Composer10), Composed[0]); types = new[] { typeof(Composer11) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); Assert.Throws(() => composers.Compose()); Console.WriteLine("throws:"); - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); var requirements = composers.GetRequirements(false); Console.WriteLine(Composers.GetComposersReport(requirements)); types = new[] { typeof(Composer2) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); Assert.Throws(() => composers.Compose()); Console.WriteLine("throws:"); - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); requirements = composers.GetRequirements(false); Console.WriteLine(Composers.GetComposersReport(requirements)); types = new[] { typeof(Composer12) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(1, Composed.Count); @@ -339,10 +341,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void DisableMissing() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); @@ -354,17 +356,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public void AttributesPriorities() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), Mock.Of(), IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); var types = new[] { typeof(Composer26) }; var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) }; - var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>(), Mock.Of()); + var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(0, Composed.Count); // 26 gone types = new[] { typeof(Composer26), typeof(Composer27) }; // 26 disabled by assembly attribute, enabled by 27 - composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>(), Mock.Of()); + composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); // both @@ -380,12 +382,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), Mock.Of()); var register = MockRegister(); - var composition = new Composition(register, typeLoader, Mock.Of(), - Mock.Of(), IOHelper, AppCaches.NoCache); + var builder = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); + var allComposers = typeLoader.GetTypes().ToList(); var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); + var composers = new Composers(builder, types, Enumerable.Empty(), Mock.Of>()); var requirements = composers.GetRequirements(); var report = Composers.GetComposersReport(requirements); Console.WriteLine(report); @@ -399,7 +401,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public class TestComposerBase : IComposer { - public virtual void Compose(Composition composition) + public virtual void Compose(IUmbracoBuilder builder) { Composed.Add(GetType()); } @@ -420,20 +422,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components public class Composer5 : TestComposerBase { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); - composition.Components().Append(); + base.Compose(builder); + builder.Components().Append(); } } [ComposeAfter(typeof(Composer5))] public class Composer5a : TestComposerBase { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); - composition.Components().Append(); + base.Compose(builder); + builder.Components().Append(); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs index cb8a88c3ec..6bc33605ac 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs @@ -1,28 +1,31 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.TestHelpers; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { [TestFixture] public class CollectionBuildersTests { - private Composition _composition; + private IUmbracoBuilder _composition; [SetUp] public void Setup() { var register = TestHelper.GetServiceCollection(); - _composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + _composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); } [TearDown] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs index fb6e95c875..66d55cda39 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing [SetUp] public void Initialize() { - ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of()); + ProfilingLogger = new ProfilingLogger(Mock.Of>(), Mock.Of()); var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs index e0a8c28518..c756023151 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; @@ -10,6 +11,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.TestHelpers; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { @@ -29,7 +31,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void LazyCollectionBuilderHandlesTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); + composition.WithCollectionBuilder() .Add() @@ -55,7 +58,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void LazyCollectionBuilderHandlesProducers() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); + composition.WithCollectionBuilder() .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) }) @@ -80,7 +84,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void LazyCollectionBuilderHandlesTypesAndProducers() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); + composition.WithCollectionBuilder() .Add() @@ -106,7 +111,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void LazyCollectionBuilderThrowsOnIllegalTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); composition.WithCollectionBuilder() .Add() @@ -128,7 +133,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing public void LazyCollectionBuilderCanExcludeTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); composition.WithCollectionBuilder() .Add() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs index b13da91a96..6ebd0c677a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Xml; using System.Xml.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NUnit.Framework; @@ -12,6 +13,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.PackageActions; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UnitTests.TestHelpers; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { @@ -23,7 +25,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing { var container = TestHelper.GetServiceCollection(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader()); + var expectedPackageActions = TypeLoader.GetPackageActions(); composition.WithCollectionBuilder() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index 7d22b0c958..8486dabcbf 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Composing var typeFinder = TestHelper.GetTypeFinder(); _typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(TestHelper.IOHelper.MapPath("~/App_Data/TEMP")), - Mock.Of>(), new ProfilingLogger(Mock.Of(), Mock.Of()), false, + Mock.Of>(), new ProfilingLogger(Mock.Of>(), Mock.Of()), false, // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver // TODO: Should probably update this so it only searches this assembly and add custom types to be found @@ -240,16 +240,16 @@ AnotherContentFinder var list3 = new[] { f1, f3, f5, f7 }; //Act - var hash1 = GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of())); - var hash2 = GetFileHash(list2, new ProfilingLogger(Mock.Of(), Mock.Of())); - var hash3 = GetFileHash(list3, new ProfilingLogger(Mock.Of(), Mock.Of())); + var hash1 = GetFileHash(list1, new ProfilingLogger(Mock.Of>(), Mock.Of())); + var hash2 = GetFileHash(list2, new ProfilingLogger(Mock.Of>(), Mock.Of())); + var hash3 = GetFileHash(list3, new ProfilingLogger(Mock.Of>(), Mock.Of())); //Assert Assert.AreNotEqual(hash1, hash2); Assert.AreNotEqual(hash1, hash3); Assert.AreNotEqual(hash2, hash3); - Assert.AreEqual(hash1, GetFileHash(list1, new ProfilingLogger(Mock.Of(), Mock.Of()))); + Assert.AreEqual(hash1, GetFileHash(list1, new ProfilingLogger(Mock.Of>(), Mock.Of()))); } [Test] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs index e6adc2eb5e..6b226e7e59 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Globalization; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Newtonsoft.Json; @@ -224,7 +225,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models private static IProfilingLogger GetTestProfilingLogger() { - var logger = NullLoggerFactory.Instance.CreateLogger("ProfilingLogger"); + var logger = NullLoggerFactory.Instance.CreateLogger(); var profiler = new TestProfiler(); return new ProfilingLogger(logger, profiler); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index 613b251249..67c294f5a9 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published { private (IPublishedContentType, IPublishedContentType) CreateContentTypes() { - var logger = Mock.Of(); + var logger = Mock.Of>(); var loggerFactory = NullLoggerFactory.Instance; var profiler = Mock.Of(); var proflog = new ProfilingLogger(logger, profiler); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs index 2fcc618397..98666ece2f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.HostedServices public class TempFileCleanupTests { private Mock _mockIOHelper; - private string _testPath = Path.GetTempPath(); + private string _testPath = Path.Combine(TestContext.CurrentContext.TestDirectory.Split("bin")[0], "App_Data", "TEMP"); [Test] public async Task Does_Not_Execute_When_Not_Main_Dom() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs index 2b78714997..183e87e5ca 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Logging/LogviewerTests.cs @@ -42,12 +42,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Logging var loggingConfiguration = TestHelper.GetLoggingConfiguration(hostingEnv); - var exampleLogfilePath = Path.Combine(testRoot, @"TestHelpers\Assets\", _logfileName); + var exampleLogfilePath = Path.Combine(testRoot, "TestHelpers","Assets", _logfileName); _newLogfileDirPath = loggingConfiguration.LogDirectory; _newLogfilePath = Path.Combine(_newLogfileDirPath, _logfileName); - var exampleSearchfilePath = Path.Combine(testRoot, @"TestHelpers\Assets\", _searchfileName); - _newSearchfileDirPath = Path.Combine(hostingEnv.ApplicationPhysicalPath, @"Config\"); + var exampleSearchfilePath = Path.Combine(testRoot, "TestHelpers","Assets", _searchfileName); + _newSearchfileDirPath = Path.Combine(hostingEnv.ApplicationPhysicalPath, @"config"); _newSearchfilePath = Path.Combine(_newSearchfileDirPath, _searchfileName); //Create/ensure Directory exists diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs new file mode 100644 index 0000000000..d021d38c15 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs @@ -0,0 +1,99 @@ +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using Microsoft.AspNetCore.Http; +using Moq; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; +using Umbraco.Web.Website.Security; +using CoreConstants = Umbraco.Core.Constants; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Security +{ + [TestFixture] + public class UmbracoWebsiteSecurityTests + { + [Test] + public void Can_Create_Registration_Model_With_Default_Member_Type() + { + var sut = CreateUmbracoWebsiteSecurity(); + + var result = sut.CreateRegistrationModel(); + AssertRegisterModel(result); + } + + [Test] + public void Can_Create_Registration_Model_With_Custom_Member_Type() + { + const string Alias = "testAlias"; + var sut = CreateUmbracoWebsiteSecurity(Alias); + + var result = sut.CreateRegistrationModel(Alias); + AssertRegisterModel(result, Alias); + } + + [Test] + public void Can_Detected_Logged_In_User() + { + var sut = CreateUmbracoWebsiteSecurity(); + + var result = sut.IsLoggedIn(); + Assert.IsTrue(result); + } + + [Test] + public void Can_Detected_Anonymous_User() + { + var sut = CreateUmbracoWebsiteSecurity(isUserAuthenticated: false); + + var result = sut.IsLoggedIn(); + Assert.IsFalse(result); + } + + private static void AssertRegisterModel(RegisterModel result, string memberTypeAlias = CoreConstants.Conventions.MemberTypes.DefaultAlias) + { + Assert.AreEqual(memberTypeAlias, result.MemberTypeAlias); + Assert.AreEqual(1, result.MemberProperties.Count); + + var firstProperty = result.MemberProperties.First(); + Assert.AreEqual("title", firstProperty.Alias); + Assert.AreEqual("Title", firstProperty.Name); + Assert.AreEqual(string.Empty, firstProperty.Value); + } + + private IUmbracoWebsiteSecurity CreateUmbracoWebsiteSecurity(string memberTypeAlias = CoreConstants.Conventions.MemberTypes.DefaultAlias, bool isUserAuthenticated = true) + { + var mockHttpContextAccessor = new Mock(); + var mockHttpContext = new Mock(); + var mockIdentity = new Mock(); + mockIdentity.SetupGet(x => x.IsAuthenticated).Returns(isUserAuthenticated); + var mockPrincipal = new Mock(); + mockPrincipal.Setup(x => x.Identity).Returns(mockIdentity.Object); + mockHttpContext.Setup(m => m.User).Returns(mockPrincipal.Object); + mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(mockHttpContext.Object); + + var mockMemberService = new Mock(); + + var mockMemberTypeService = new Mock(); + mockMemberTypeService + .Setup(x => x.Get(It.Is(y => y == memberTypeAlias))) + .Returns(CreateSimpleMemberType(memberTypeAlias)); + + var mockShortStringHelper = new Mock(); + + return new UmbracoWebsiteSecurity(mockHttpContextAccessor.Object, mockMemberService.Object, mockMemberTypeService.Object, mockShortStringHelper.Object); + } + + private IMemberType CreateSimpleMemberType(string alias) + { + var memberType = MemberTypeBuilder.CreateSimpleMemberType(alias); + memberType.SetMemberCanEditProperty("title", true); + return memberType; + } + } +} diff --git a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs index 3598c75cf7..8d2a6eb217 100644 --- a/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs +++ b/src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs @@ -4,6 +4,7 @@ using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Events; @@ -26,13 +27,13 @@ namespace Umbraco.Tests.Cache [UmbracoTest(WithApplication = true)] public class DistributedCacheBinderTests : UmbracoTestBase { - protected override void Compose(Composition composition) + protected override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); // refreshers.HandleEvents wants a UmbracoContext // which wants these - composition.Services.AddUnique(_ => Mock.Of()); - composition.WithCollectionBuilder(); + builder.Services.AddUnique(Mock.Of()); + builder.WithCollectionBuilder(); } [Test] diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index cfcf7a82d8..2e377a0617 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -33,7 +33,7 @@ namespace Umbraco.Tests.Cache.PublishedCache { base.Compose(); - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .Clear() .Append(); diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index 8623b015a4..170e5e357e 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -1,6 +1,7 @@ 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; @@ -17,6 +18,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Web; +using Umbraco.Web.Common.Builder; using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.IO @@ -32,15 +34,8 @@ namespace Umbraco.Tests.IO { _register = TestHelper.GetRegister(); - var composition = new Composition( - _register, - TestHelper.GetMockedTypeLoader(), - Mock.Of(), - Mock.Of(), - TestHelper.IOHelper, - AppCaches.NoCache - ); - + var composition = new UmbracoBuilder(_register, Mock.Of(), TestHelper.GetMockedTypeLoader()); + composition.Services.AddTransient(_ => Mock.Of()); composition.Services.AddTransient(); composition.Services.AddTransient(typeof(ILogger<>), typeof(Logger<>)); diff --git a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs index c94f9f5403..b48e3230f6 100644 --- a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs @@ -58,7 +58,7 @@ namespace Umbraco.Tests.Packaging // pollute everything, they are ignored by the type finder and explicitely // added to the editors collection - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .Add() .Add(); } @@ -70,7 +70,7 @@ namespace Umbraco.Tests.Packaging if (!withApplication) return; // re-register with actual media fs - Composition.ComposeFileSystems(); + Builder.ComposeFileSystems(); } private PackageDataInstallation PackageDataInstallation => Factory.GetRequiredService(); diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 76e2c52978..d3c9eaf36d 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -20,6 +21,7 @@ using Umbraco.Core.Strings; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Web; +using Umbraco.Web.Common.Builder; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published @@ -35,14 +37,7 @@ namespace Umbraco.Tests.Published // Current.Reset(); var register = TestHelper.GetRegister(); - var composition = new Composition( - register, - TestHelper.GetMockedTypeLoader(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - AppCaches.NoCache - ); + var composition = new UmbracoBuilder(register, Mock.Of(), TestHelper.GetMockedTypeLoader()); composition.WithCollectionBuilder() .Append() diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index 78cae13b13..a17eb71ab0 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -32,6 +32,7 @@ using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; using Current = Umbraco.Web.Composing.Current; using Umbraco.Core.Serialization; +using Umbraco.Net; namespace Umbraco.Tests.PublishedContent { @@ -147,8 +148,10 @@ namespace Umbraco.Tests.PublishedContent // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; + var lifetime = new Mock(); _snapshotService = new PublishedSnapshotService(options, null, + lifetime.Object, runtime, serviceContext, contentTypeFactory, @@ -173,6 +176,7 @@ namespace Umbraco.Tests.PublishedContent // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); + lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); Mock.Get(factory).Setup(x => x.GetService(typeof(IVariationContextAccessor))).Returns(_variationAccesor); } diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index af2f738cf7..d689215081 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -21,6 +21,7 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; +using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; @@ -188,8 +189,10 @@ namespace Umbraco.Tests.PublishedContent // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; + var lifetime = new Mock(); _snapshotService = new PublishedSnapshotService(options, null, + lifetime.Object, runtime, serviceContext, contentTypeFactory, @@ -212,6 +215,8 @@ namespace Umbraco.Tests.PublishedContent TestHelper.IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); + lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); + // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index 547e7a637f..edcd199463 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.PublishedContent { base.Compose(); - Composition.Services.AddUnique(_ => GetServiceContext()); + Builder.Services.AddUnique(GetServiceContext()); } protected ServiceContext GetServiceContext() diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index c67382d093..75983ba41a 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.PublishedContent { base.Compose(); - Composition.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); + Builder.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); } protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index 582411635d..b55609858b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -18,6 +18,7 @@ using Umbraco.Web.Routing; using Umbraco.Core.Media; using System; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Security; using Umbraco.Core.Serialization; namespace Umbraco.Tests.PublishedContent @@ -34,7 +35,7 @@ namespace Umbraco.Tests.PublishedContent // FIXME: what about the if (PropertyValueConvertersResolver.HasCurrent == false) ?? // can we risk double - registering and then, what happens? - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .Clear() .Append() .Append() @@ -57,7 +58,7 @@ namespace Umbraco.Tests.PublishedContent var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new RichTextPropertyEditor( loggerFactory, - Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of(), imageSourceParser, diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index b8de80fdb1..2170da2f75 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -28,6 +28,7 @@ using Umbraco.Web.Templates; using Umbraco.Web.Routing; using Current = Umbraco.Web.Composing.Current; using Umbraco.Core.Media; +using Umbraco.Core.Security; using Umbraco.Core.Serialization; namespace Umbraco.Tests.PublishedContent @@ -43,17 +44,18 @@ namespace Umbraco.Tests.PublishedContent { base.Compose(); _publishedSnapshotAccessorMock = new Mock(); - Composition.Services.AddUnique(_publishedSnapshotAccessorMock.Object); + Builder.Services.AddUnique(_publishedSnapshotAccessorMock.Object); - Composition.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(f => new PublishedModelFactory(f.GetRequiredService().GetTypes(), f.GetRequiredService())); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); var loggerFactory = NullLoggerFactory.Instance; var mediaService = Mock.Of(); var mediaFileService = Mock.Of(); var contentTypeBaseServiceProvider = Mock.Of(); var umbracoContextAccessor = Mock.Of(); + var backOfficeSecurityAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); var serializer = new ConfigurationEditorJsonSerializer(); @@ -64,11 +66,11 @@ namespace Umbraco.Tests.PublishedContent var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper), serializer) { Id = 1 }, new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(loggerFactory,umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of()), serializer) { Id = 1002 }, + new DataType(new RichTextPropertyEditor(loggerFactory,backOfficeSecurityAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of()), serializer) { Id = 1002 }, new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService), serializer) { Id = 1003 }, new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1004 }, new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1005 }); - Composition.Services.AddUnique(f => dataTypeService); + Builder.Services.AddUnique(f => dataTypeService); } protected override void Initialize() diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index c53cbea9e9..9262c72dfa 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -43,11 +43,11 @@ namespace Umbraco.Tests.PublishedContent { base.Compose(); - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .Clear() .Append(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); } private IMediaType MakeNewMediaType(IUser user, string text, int parentId = -1) diff --git a/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs b/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs index 84e22c7760..d9c6021534 100644 --- a/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs +++ b/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs @@ -20,7 +20,7 @@ namespace Umbraco.Tests.Routing protected override void Compose() { base.Compose(); - Composition.Services.AddTransient(); + Builder.Services.AddTransient(); } protected override void ComposeSettings() @@ -28,8 +28,8 @@ namespace Umbraco.Tests.Routing var contentSettings = new ContentSettings(); var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); } protected IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index edcbf858e2..c51ca27b8c 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.Routing { base.Compose(); - Composition.Services.AddTransient(); + Builder.Services.AddTransient(); } private void SetDomains1() diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index b3663738dd..9332dc894a 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -5,23 +5,17 @@ using System.Web.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Runtime; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Common.Builders; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; @@ -31,7 +25,6 @@ using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Umbraco.Web.Runtime; using Umbraco.Web.WebApi; -using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Routing @@ -53,15 +46,6 @@ namespace Umbraco.Tests.Routing HostingEnvironment); } - public class TestRuntimeBootstrapper : CoreRuntimeBootstrapper - { - public TestRuntimeBootstrapper(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - : base(globalSettings, connectionStrings,umbracoVersion, ioHelper, NullLoggerFactory.Instance, Mock.Of(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache) - { - } - - } - protected override void Compose() { base.Compose(); @@ -72,11 +56,11 @@ namespace Umbraco.Tests.Routing // var surfaceControllerTypes = new SurfaceControllerTypeCollection(Composition.TypeLoader.GetSurfaceControllers()); // Composition.Services.AddUnique(surfaceControllerTypes); - var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Composition.TypeLoader.GetUmbracoApiControllers()); - Composition.Services.AddUnique(umbracoApiControllerTypes); + var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Builder.TypeLoader.GetUmbracoApiControllers()); + Builder.Services.AddUnique(umbracoApiControllerTypes); var requestHandlerSettings = new RequestHandlerSettings(); - Composition.Services.AddUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); + Builder.Services.AddUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } public override void TearDown() diff --git a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs index eba88383e7..c403ade51c 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Routing protected override void ComposeSettings() { base.ComposeSettings(); - Composition.Services.AddUnique(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); + Builder.Services.AddUnique(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); } [TestCase(1046, "/")] diff --git a/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs index 9e0d311188..fd87ce84b1 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Routing protected override void ComposeSettings() { base.ComposeSettings(); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); } /// diff --git a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs index 346af19a4c..4c658379cd 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Routing { base.Compose(); - Composition.Services.AddUnique(_ => GetServiceContext()); + Builder.Services.AddUnique(GetServiceContext()); } protected ServiceContext GetServiceContext() diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index 5fef721dfa..80b92b4d1b 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -25,8 +25,8 @@ namespace Umbraco.Tests.Routing { base.Compose(); - Composition.Services.AddUnique(_ => Mock.Of()); - Composition.Services.AddTransient(); + Builder.Services.AddUnique(Mock.Of()); + Builder.Services.AddTransient(); } void SetDomains1() diff --git a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs index f367db2123..10cb8c9ac4 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -27,8 +27,8 @@ namespace Umbraco.Tests.Routing protected override void Compose() { base.Compose(); - Composition.Services.AddUnique(_ => Mock.Of()); - Composition.Services.AddTransient(); + Builder.Services.AddUnique(Mock.Of()); + Builder.Services.AddTransient(); } [Test] diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index 59f9a43526..5ab6aeaa1d 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging; using Moq; @@ -20,6 +21,7 @@ using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Web; using Current = Umbraco.Web.Composing.Current; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Web.Common.Builder; namespace Umbraco.Tests.Scoping { @@ -38,7 +40,7 @@ namespace Umbraco.Tests.Scoping var services = TestHelper.GetRegister(); - var composition = new Composition(services, TestHelper.GetMockedTypeLoader(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(services, Mock.Of(), TestHelper.GetMockedTypeLoader()); _testObjects = new TestObjects(services); diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 5968a13ce8..1a8e485634 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; +using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -43,10 +44,10 @@ namespace Umbraco.Tests.Scoping // but then, it requires a lot of plumbing ;( // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess - Composition.Services.AddUnique(); - Composition.Services.AddUnique(f => Mock.Of()); - Composition.WithCollectionBuilder() - .Add(() => Composition.TypeLoader.GetCacheRefreshers()); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(f => Mock.Of()); + Builder.WithCollectionBuilder() + .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } public override void TearDown() @@ -83,10 +84,11 @@ namespace Umbraco.Tests.Scoping var typeFinder = TestHelper.GetTypeFinder(); var nuCacheSettings = new NuCacheSettings(); - - return new PublishedSnapshotService( + var lifetime = new Mock(); + var snapshotService = new PublishedSnapshotService( options, null, + lifetime.Object, runtimeStateMock.Object, ServiceContext, contentTypeFactory, @@ -106,6 +108,10 @@ namespace Umbraco.Tests.Scoping Mock.Of(), IOHelper, Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); + + lifetime.Raise(e => e.ApplicationInit += null, EventArgs.Empty); + + return snapshotService; } protected IUmbracoContext GetUmbracoContextNu(string url, RouteData routeData = null, bool setSingleton = false) diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 3a07a9864a..6814210cc4 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -38,10 +38,10 @@ namespace Umbraco.Tests.Scoping // but then, it requires a lot of plumbing ;( // FIXME: and we cannot inject a DistributedCache yet // so doing all this mess - Composition.Services.AddUnique(); - Composition.Services.AddUnique(f => Mock.Of()); - Composition.WithCollectionBuilder() - .Add(() => Composition.TypeLoader.GetCacheRefreshers()); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(f => Mock.Of()); + Builder.WithCollectionBuilder() + .Add(() => Builder.TypeLoader.GetCacheRefreshers()); } protected override void ComposeSettings() @@ -50,9 +50,9 @@ namespace Umbraco.Tests.Scoping var globalSettings = new GlobalSettings(); var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); } [TearDown] diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index ddfc6fa7f1..a048c76022 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Moq; using NPoco; @@ -14,6 +15,7 @@ using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence; using Umbraco.Persistance.SqlCe; using Umbraco.Web; +using Umbraco.Web.Common.Builder; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.TestHelpers @@ -38,7 +40,7 @@ namespace Umbraco.Tests.TestHelpers var services = TestHelper.GetRegister(); var ioHelper = TestHelper.IOHelper; - var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); + var logger = new ProfilingLogger(Mock.Of>(), Mock.Of()); var typeFinder = TestHelper.GetTypeFinder(); var typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), @@ -46,7 +48,8 @@ namespace Umbraco.Tests.TestHelpers logger, false); - var composition = new Composition(services, typeLoader, Mock.Of(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new UmbracoBuilder(services, Mock.Of(), TestHelper.GetMockedTypeLoader()); + services.AddUnique(_ => Mock.Of()); services.AddUnique(_ => NullLoggerFactory.Instance); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index eaa186bef6..c6587f6ad8 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -37,8 +37,8 @@ namespace Umbraco.Tests.TestHelpers { base.Compose(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); } protected override void Initialize() @@ -109,7 +109,7 @@ namespace Umbraco.Tests.TestHelpers contentFinders ?? new ContentFinderCollection(Enumerable.Empty()), new TestLastChanceFinder(), new TestVariationContextAccessor(), - new ProfilingLogger(Mock.Of(), Mock.Of()), + new ProfilingLogger(Mock.Of>(), Mock.Of()), Mock.Of>(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 53a7e7ba36..faf387528d 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -73,18 +73,18 @@ namespace Umbraco.Tests.TestHelpers { base.Compose(); - Composition.Services.AddTransient(); - Composition.Services.AddTransient(factory => PublishedSnapshotService); - Composition.Services.AddTransient(factory => DefaultCultureAccessor); + Builder.Services.AddTransient(); + Builder.Services.AddTransient(factory => PublishedSnapshotService); + Builder.Services.AddTransient(factory => DefaultCultureAccessor); - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .Clear() - .Add(() => Composition.TypeLoader.GetDataEditors()); + .Add(() => Builder.TypeLoader.GetDataEditors()); - Composition.WithCollectionBuilder() - .Add(Composition.TypeLoader.GetUmbracoApiControllers()); + Builder.WithCollectionBuilder() + .Add(Builder.TypeLoader.GetUmbracoApiControllers()); - Composition.Services.AddUnique(f => + Builder.Services.AddUnique(f => { if (Options.Database == UmbracoTestOptions.Database.None) return TestObjects.GetDatabaseFactoryMock(); diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 9c259d7d16..2d9c66806b 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -19,6 +19,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Templates; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; @@ -63,11 +64,11 @@ namespace Umbraco.Tests.Testing.TestingTests public void Can_Mock_Umbraco_Helper() { // unless we can inject them in MembershipHelper, we need need this - Composition.Services.AddTransient(_ => Mock.Of()); - Composition.Services.AddTransient(_ => Mock.Of()); - Composition.Services.AddTransient(_ => Mock.Of()); - Composition.Services.AddTransient(_ => AppCaches.Disabled); - Composition.Services.AddTransient(); + Builder.Services.AddTransient(_ => Mock.Of()); + Builder.Services.AddTransient(_ => Mock.Of()); + Builder.Services.AddTransient(_ => Mock.Of()); + Builder.Services.AddTransient(_ => AppCaches.Disabled); + Builder.Services.AddTransient(); // ReSharper disable once UnusedVariable var helper = new UmbracoHelper(Mock.Of(), @@ -113,7 +114,7 @@ namespace Umbraco.Tests.Testing.TestingTests var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, NullLoggerFactory.Instance, ShortStringHelper, Mock.Of()); var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of() })); - var umbracoApiController = new FakeUmbracoApiController(new GlobalSettings(), Mock.Of(), Mock.Of(), ServiceContext.CreatePartial(), AppCaches.NoCache, profilingLogger , Mock.Of(), umbracoMapper, Mock.Of()); + var umbracoApiController = new FakeUmbracoApiController(new GlobalSettings(), Mock.Of(), Mock.Of(), Mock.Of(), ServiceContext.CreatePartial(), AppCaches.NoCache, profilingLogger , Mock.Of(), umbracoMapper, Mock.Of()); Assert.Pass(); } @@ -121,7 +122,7 @@ namespace Umbraco.Tests.Testing.TestingTests internal class FakeUmbracoApiController : UmbracoApiController { - public FakeUmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } + public FakeUmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + : base(globalSettings, umbracoContextAccessor, backOfficeSecurityAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 4466b9424e..b780665c23 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -9,6 +9,7 @@ using System.Web.Routing; using System.Web.Security; using System.Xml.Linq; using Examine; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -16,6 +17,7 @@ using Moq; using NUnit.Framework; using Serilog; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Composing.CompositionExtensions; @@ -50,6 +52,7 @@ using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; using Umbraco.Web.Actions; using Umbraco.Web.AspNet; +using Umbraco.Web.Common.Builder; using Umbraco.Web.ContentApps; using Umbraco.Web.Hosting; using Umbraco.Web.Install; @@ -103,7 +106,7 @@ namespace Umbraco.Tests.Testing // test feature, and no test "base" class should be. only actual test feature classes // should be marked with that attribute. - protected Composition Composition { get; private set; } + protected IUmbracoBuilder Builder { get; private set; } protected IServiceProvider Factory { get; private set; } @@ -186,7 +189,7 @@ namespace Umbraco.Tests.Testing _loggerFactory = loggerFactory; var profiler = new LogProfiler(loggerFactory.CreateLogger()); var msLogger = loggerFactory.CreateLogger("msLogger"); - var proflogger = new ProfilingLogger(loggerFactory.CreateLogger("ProfilingLogger"), profiler); + var proflogger = new ProfilingLogger(loggerFactory.CreateLogger(), profiler); IOHelper = TestHelper.IOHelper; TypeFinder = new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); @@ -204,15 +207,7 @@ namespace Umbraco.Tests.Testing var services = TestHelper.GetRegister(); - - Composition = new Composition( - services, - typeLoader, - proflogger, - MockRuntimeState(RuntimeLevel.Run), - TestHelper.IOHelper, - AppCaches.NoCache - ); + Builder = new UmbracoBuilder(services, Mock.Of(), typeLoader); //TestHelper.GetConfigs().RegisterWith(register); services.AddUnique(typeof(ILoggerFactory), loggerFactory); @@ -248,7 +243,7 @@ namespace Umbraco.Tests.Testing TestObjects = new TestObjects(services); Compose(); - Current.Factory = Factory = Composition.CreateServiceProvider(); + Current.Factory = Factory = Builder.CreateServiceProvider(); Initialize(); } @@ -263,10 +258,10 @@ namespace Umbraco.Tests.Testing ComposeMisc(); // not sure really - Compose(Composition); + Compose(Builder); } - protected virtual void Compose(Composition composition) + protected virtual void Compose(IUmbracoBuilder builder) { } protected virtual void Initialize() @@ -312,19 +307,21 @@ namespace Umbraco.Tests.Testing Umbraco.Web.Composing.Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); // web - Composition.Services.AddUnique(_ => Umbraco.Web.Composing.Current.UmbracoContextAccessor); - Composition.Services.AddUnique(); - Composition.WithCollectionBuilder(); + Builder.Services.AddUnique(Current.UmbracoContextAccessor); + Builder.Services.AddUnique(new HybridBackofficeSecurityAccessor(AppCaches.NoCache.RequestCache)); + Builder.Services.AddUnique(); + Builder.WithCollectionBuilder(); - Composition.DataValueReferenceFactories(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.SetCultureDictionaryFactory(); - Composition.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); + Builder.DataValueReferenceFactories(); + + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.SetCultureDictionaryFactory(); + Builder.Services.AddSingleton(f => f.GetRequiredService().CreateDictionary()); // register back office sections in the order we want them rendered - Composition.WithCollectionBuilder().Append() + Builder.WithCollectionBuilder().Append() .Append() .Append() .Append() @@ -332,18 +329,18 @@ namespace Umbraco.Tests.Testing .Append() .Append() .Append(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); var webRoutingSettings = new WebRoutingSettings(); - Composition.Services.AddUnique(factory => + Builder.Services.AddUnique(factory => new UrlProvider( factory.GetRequiredService(), Microsoft.Extensions.Options.Options.Create(webRoutingSettings), @@ -360,25 +357,25 @@ namespace Umbraco.Tests.Testing // what else? var runtimeStateMock = new Mock(); runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run); - Composition.Services.AddUnique(f => runtimeStateMock.Object); - Composition.Services.AddTransient(_ => Mock.Of()); - Composition.Services.AddTransient(); + Builder.Services.AddUnique(f => runtimeStateMock.Object); + Builder.Services.AddTransient(_ => Mock.Of()); + Builder.Services.AddTransient(); // ah... - Composition.WithCollectionBuilder(); - Composition.WithCollectionBuilder(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.WithCollectionBuilder(); + Builder.WithCollectionBuilder(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); // register empty content apps collection - Composition.WithCollectionBuilder(); + Builder.WithCollectionBuilder(); // manifest - Composition.ManifestValueValidators(); - Composition.ManifestFilters(); - Composition.MediaUrlGenerators() + Builder.ManifestValueValidators(); + Builder.ManifestFilters(); + Builder.MediaUrlGenerators() .Add() .Add(); @@ -388,7 +385,7 @@ namespace Umbraco.Tests.Testing { if (configure == false) return; - Composition + Builder .ComposeCoreMappingProfiles(); } @@ -442,13 +439,13 @@ namespace Umbraco.Tests.Testing var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); var webRoutingSettings = new WebRoutingSettings(); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(coreDebugSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(requestHandlerSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); - Composition.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(coreDebugSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(requestHandlerSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); + Builder.Services.AddTransient(x => Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); } protected virtual void ComposeApplication(bool withApplication) @@ -458,69 +455,69 @@ namespace Umbraco.Tests.Testing if (withApplication == false) return; // default Datalayer/Repositories/SQL/Database/etc... - Composition.ComposeRepositories(); + Builder.ComposeRepositories(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); // register filesystems - Composition.Services.AddUnique(factory => TestObjects.GetFileSystemsMock()); + Builder.Services.AddUnique(factory => TestObjects.GetFileSystemsMock()); var scheme = Mock.Of(); var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, _loggerFactory.CreateLogger(), TestHelper.ShortStringHelper); - Composition.Services.AddUnique(factory => mediaFileSystem); + Builder.Services.AddUnique(factory => mediaFileSystem); // no factory (noop) - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); // register application stuff (database factory & context, services...) - Composition.WithCollectionBuilder() + Builder.WithCollectionBuilder() .AddCoreMappers(); - Composition.Services.AddUnique(_ => new TransientEventMessagesFactory()); + Builder.Services.AddUnique(_ => new TransientEventMessagesFactory()); var globalSettings = new GlobalSettings(); var connectionStrings = new ConnectionStrings(); - Composition.Services.AddUnique(f => new UmbracoDatabaseFactory(_loggerFactory.CreateLogger(), + Builder.Services.AddUnique(f => new UmbracoDatabaseFactory(_loggerFactory.CreateLogger(), LoggerFactory, globalSettings, connectionStrings, new Lazy(f.GetRequiredService), TestHelper.DbProviderFactoryCreator)); - Composition.Services.AddUnique(f => f.GetService().SqlContext); + Builder.Services.AddUnique(f => f.GetService().SqlContext); - Composition.WithCollectionBuilder(); // empty + Builder.WithCollectionBuilder(); // empty - Composition.Services.AddUnique(factory + Builder.Services.AddUnique(factory => TestObjects.GetScopeProvider(_loggerFactory, factory.GetService(), factory.GetService(), factory.GetService())); - Composition.Services.AddUnique(factory => (IScopeAccessor) factory.GetRequiredService()); + Builder.Services.AddUnique(factory => (IScopeAccessor) factory.GetRequiredService()); - Composition.ComposeServices(); + Builder.ComposeServices(); // composition root is doing weird things, fix - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); // somehow property editor ends up wanting this - Composition.WithCollectionBuilder(); + Builder.WithCollectionBuilder(); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); // note - don't register collections, use builders - Composition.WithCollectionBuilder(); - Composition.Services.AddUnique(); - Composition.Services.AddUnique(); + Builder.WithCollectionBuilder(); + Builder.Services.AddUnique(); + Builder.Services.AddUnique(); - Composition.Services.AddUnique(TestHelper.GetHttpContextAccessor(GetHttpContextFactory("/").HttpContext)); + Builder.Services.AddUnique(TestHelper.GetHttpContextAccessor(GetHttpContextFactory("/").HttpContext)); } #endregion diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index ab8884cbaf..59b453cc5b 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -1,4 +1,5 @@ using System.IO; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Umbraco.Core; @@ -20,7 +21,7 @@ namespace Umbraco.Tests.UmbracoExamine { // var logger = new SerilogLogger(new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config"))); - _profilingLogger = new ProfilingLogger(NullLogger.Instance, new LogProfiler(NullLogger.Instance)); + _profilingLogger = new ProfilingLogger(NullLoggerFactory.Instance.CreateLogger(), new LogProfiler(NullLogger.Instance)); } private IProfilingLogger _profilingLogger; @@ -35,7 +36,7 @@ namespace Umbraco.Tests.UmbracoExamine { base.Compose(); var requestHandlerSettings = new RequestHandlerSettings(); - Composition.Services.AddUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); + Builder.Services.AddUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } } } diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index 040799a09a..39eef86a98 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -159,7 +159,7 @@ namespace Umbraco.Tests.UmbracoExamine public static IProfilingLogger GetMockProfilingLogger() { - return new ProfilingLogger(Mock.Of(), Mock.Of()); + return new ProfilingLogger(Mock.Of>(), Mock.Of()); } public static UmbracoContentIndex GetUmbracoIndexer( diff --git a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs index 0cb990df3d..cdc2bfed00 100644 --- a/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/AuthenticationControllerTests.cs @@ -51,12 +51,12 @@ namespace Umbraco.Tests.Web.Controllers // replace the true IUserService implementation with a mock // so that each test can configure the service to their liking - Composition.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); // kill the true IEntityService too - Composition.Services.AddUnique(f => Mock.Of()); + Builder.Services.AddUnique(f => Mock.Of()); - Composition.Services.AddUnique(); + Builder.Services.AddUnique(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 4441d1b2f3..1b414279a4 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -3,17 +3,19 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; -using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Security; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; @@ -25,12 +27,10 @@ using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.Security; +using Umbraco.Web.Editors.Filters; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; -using Microsoft.AspNetCore.Identity; -using Umbraco.Web.Editors.Filters; namespace Umbraco.Web.BackOffice.Controllers { diff --git a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs index b4143831d5..f7508e920f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Strings.Css; @@ -35,7 +36,8 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IHostingEnvironment _hostingEnvironment; private readonly IFileSystems _fileSystems; private readonly IFileService _fileService; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + private readonly ILocalizedTextService _localizedTextService; private readonly UmbracoMapper _umbracoMapper; private readonly IShortStringHelper _shortStringHelper; @@ -45,7 +47,7 @@ namespace Umbraco.Web.BackOffice.Controllers IHostingEnvironment hostingEnvironment, IFileSystems fileSystems, IFileService fileService, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ILocalizedTextService localizedTextService, UmbracoMapper umbracoMapper, IShortStringHelper shortStringHelper, @@ -54,7 +56,7 @@ namespace Umbraco.Web.BackOffice.Controllers _hostingEnvironment = hostingEnvironment; _fileSystems = fileSystems; _fileService = fileService; - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _localizedTextService = localizedTextService; _umbracoMapper = umbracoMapper; _shortStringHelper = shortStringHelper; @@ -73,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (display == null) throw new ArgumentNullException("display"); if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Value cannot be null or whitespace.", "type"); - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; switch (type) { case Core.Constants.Trees.PartialViews: @@ -323,7 +325,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (string.IsNullOrWhiteSpace(virtualPath)) throw new ArgumentException("Value cannot be null or whitespace.", "virtualPath"); virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath); - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; switch (type) { case Constants.Trees.PartialViews: @@ -556,7 +558,7 @@ namespace Umbraco.Web.BackOffice.Controllers ? relPath + display.Name : relPath.EnsureEndsWith('/') + display.Name; } - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; var file = getFileByName(relPath); if (file != null) { @@ -609,7 +611,7 @@ namespace Umbraco.Web.BackOffice.Controllers display.Name = EnsureCorrectFileExtension(display.Name, ".cshtml"); Attempt partialViewResult; - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; var virtualPath = NormalizeVirtualPath(display.VirtualPath, systemDirectory); var view = getView(virtualPath); diff --git a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs index 4d12f8db0c..41e5cfb589 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Dashboards; +using Umbraco.Core.Security; using Umbraco.Web.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -32,7 +33,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoBackOfficeAuthorize] public class DashboardController : UmbracoApiController { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly AppCaches _appCaches; private readonly ILogger _logger; private readonly IDashboardService _dashboardService; @@ -43,18 +44,15 @@ namespace Umbraco.Web.BackOffice.Controllers /// Initializes a new instance of the with all its dependencies. /// public DashboardController( - IUmbracoContextAccessor umbracoContextAccessor, - ISqlContext sqlContext, - ServiceContext services, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, AppCaches appCaches, ILogger logger, - IRuntimeState runtimeState, IDashboardService dashboardService, IUmbracoVersion umbracoVersion, IShortStringHelper shortStringHelper) { - _umbracoContextAccessor = umbracoContextAccessor; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _appCaches = appCaches; _logger = logger; _dashboardService = dashboardService; @@ -69,7 +67,7 @@ namespace Umbraco.Web.BackOffice.Controllers [ValidateAngularAntiForgeryToken] public async Task GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/") { - var user = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var user = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; var allowedSections = string.Join(",", user.AllowedSections); var language = user.Language; var version = _umbracoVersion.SemanticVersion.ToSemanticString(); @@ -214,7 +212,7 @@ namespace Umbraco.Web.BackOffice.Controllers [TypeFilter(typeof(OutgoingEditorModelEventAttribute))] public IEnumerable> GetDashboard(string section) { - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; return _dashboardService.GetDashboards(section, currentUser).Select(x => new Tab { Id = x.Id, diff --git a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs index c88d0d16c9..24c5b1cb24 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; @@ -43,7 +44,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMediaTypeService _mediaTypeService; private readonly IMemberTypeService _memberTypeService; private readonly ILocalizedTextService _localizedTextService; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IConfigurationEditorJsonSerializer _serializer; public DataTypeController( @@ -56,7 +57,7 @@ namespace Umbraco.Web.BackOffice.Controllers IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, ILocalizedTextService localizedTextService, - IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IConfigurationEditorJsonSerializer serializer) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); @@ -68,7 +69,7 @@ namespace Umbraco.Web.BackOffice.Controllers _mediaTypeService = mediaTypeService ?? throw new ArgumentNullException(nameof(mediaTypeService)); _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); - _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _backOfficeSecurityAccessor = backOfficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backOfficeSecurityAccessor)); _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); } @@ -149,7 +150,7 @@ namespace Umbraco.Web.BackOffice.Controllers { throw new HttpResponseException(HttpStatusCode.NotFound); } - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; _dataTypeService.Delete(foundType, currentUser.Id); return Ok(); @@ -249,7 +250,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult DeleteContainer(int id) { - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; _dataTypeService.DeleteContainer(id, currentUser.Id); return Ok(); @@ -257,7 +258,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostCreateContainer(int parentId, string name) { - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; var result = _dataTypeService.CreateContainer(parentId, name, currentUser.Id); return result @@ -287,7 +288,7 @@ namespace Umbraco.Web.BackOffice.Controllers dataType.PersistedDataType.Configuration = configuration; - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; // save the data type try { @@ -344,7 +345,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostRenameContainer(int id, string name) { - var currentUser = _umbracoContextAccessor.GetRequiredUmbracoContext().Security.CurrentUser; + var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser; var result = _dataTypeService.RenameContainer(id, name, currentUser.Id); return result diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 5b104d2f9b..28c077a63c 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -250,7 +250,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// The culture to fetch the URL for /// The URL or path to the item [DetermineAmbiguousActionByPassingParameters] - public HttpResponseMessage GetUrl(Udi udi, string culture = "*") + public IActionResult GetUrl(Udi udi, string culture = "*") { var intId = _entityService.GetId(udi); if (!intId.Success) @@ -284,7 +284,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// We are not restricting this with security because there is no sensitive data /// [DetermineAmbiguousActionByPassingParameters] - public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type, string culture = null) + public IActionResult GetUrl(int id, UmbracoEntityTypes type, string culture = null) { culture = culture ?? ClientCulture(); @@ -297,10 +297,7 @@ namespace Umbraco.Web.BackOffice.Controllers { returnUrl = foundUrl; - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(returnUrl) - }; + return Ok(returnUrl); } } @@ -314,10 +311,7 @@ namespace Umbraco.Web.BackOffice.Controllers returnUrl = "/" + string.Join("/", ancestors.Select(x => x.Name)); - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(returnUrl) - }; + return Ok(returnUrl); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs index a878910bf3..d11b89f6f0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs @@ -157,7 +157,7 @@ namespace Umbraco.Web.BackOffice.Controllers } [HttpPost] - public HttpResponseMessage CreatePartialViewMacroWithFile(CreatePartialViewMacroWithFileModel model) + public IActionResult CreatePartialViewMacroWithFile(CreatePartialViewMacroWithFileModel model) { if (model == null) throw new ArgumentNullException("model"); if (string.IsNullOrWhiteSpace(model.Filename)) throw new ArgumentException("Filename cannot be null or whitespace", "model.Filename"); @@ -173,7 +173,7 @@ namespace Umbraco.Web.BackOffice.Controllers }; _macroService.Save(macro); // may throw - return new HttpResponseMessage(HttpStatusCode.OK); + return Ok(); } public class CreatePartialViewMacroWithFileModel diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index 93c6576d4e..5b78179f4c 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs @@ -18,36 +18,6 @@ namespace Umbraco.Extensions { public static class BackOfficeServiceCollectionExtensions { - /// - /// Adds the services required for running the Umbraco back office - /// - /// - public static void AddUmbracoBackOffice(this IServiceCollection services) - { - services.AddAntiforgery(); - - // TODO: We had this check in v8 where we don't enable these unless we can run... - //if (runtimeState.Level != RuntimeLevel.Upgrade && runtimeState.Level != RuntimeLevel.Run) return app; - - services.AddSingleton(); - services - .AddAuthentication(Constants.Security.BackOfficeAuthenticationType) - .AddCookie(Constants.Security.BackOfficeAuthenticationType) - .AddCookie(Constants.Security.BackOfficeExternalAuthenticationType, o => - { - o.Cookie.Name = Constants.Security.BackOfficeExternalAuthenticationType; - o.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }); - - // TODO: Need to add more cookie options, see https://github.com/dotnet/aspnetcore/blob/3.0/src/Identity/Core/src/IdentityServiceCollectionExtensions.cs#L45 - - services.ConfigureOptions(); - } - - public static void AddUmbracoPreview(this IServiceCollection services) - { - services.AddSignalR(); - } /// /// Adds the services required for using Umbraco back office Identity diff --git a/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs index 2a8a2e900d..4e8fe01b7f 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/CompositionExtensions.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Composing; +using Umbraco.Core.Builder; +using Umbraco.Core.Composing; using Umbraco.Web.BackOffice.Trees; // the namespace here is intentional - although defined in Umbraco.Web assembly, @@ -18,10 +19,10 @@ namespace Umbraco.Extensions /// /// Gets the back office tree collection builder /// - /// + /// /// - public static TreeCollectionBuilder Trees(this Composition composition) - => composition.WithCollectionBuilder(); + public static TreeCollectionBuilder Trees(this IUmbracoBuilder builder) + => builder.WithCollectionBuilder(); #endregion } diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs index c494425274..76fd4a46f7 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs @@ -1,33 +1,63 @@ -using Umbraco.Web.Common.Builder; +using System; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Builder; +using Umbraco.Web.BackOffice.Filters; +using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.Common.Builder; namespace Umbraco.Extensions { public static class UmbracoBuilderExtensions { - public static IUmbracoBuilder WithAllBackOfficeComponents(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddAllBackOfficeComponents(this IUmbracoBuilder builder) { return builder - .WithConfiguration() - .WithCore() - .WithWebComponents() - .WithRuntimeMinifier() - .WithBackOffice() - .WithBackOfficeIdentity() - .WithMiniProfiler() - .WithMvcAndRazor() - .WithWebServer() - .WithPreview() - .WithHostedServices() - .WithHttpClients(); + .AddConfiguration() + .AddUmbracoCore() + .AddWebComponents() + .AddRuntimeMinifier() + .AddBackOffice() + .AddBackOfficeIdentity() + .AddMiniProfiler() + .AddMvcAndRazor() + .AddWebServer() + .AddPreviewSupport() + .AddHostedServices() + .AddHttpClients(); } - public static IUmbracoBuilder WithBackOffice(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithBackOffice), () => builder.Services.AddUmbracoBackOffice()); + public static IUmbracoBuilder AddBackOffice(this IUmbracoBuilder builder) + { + builder.Services.AddAntiforgery(); + builder.Services.AddSingleton(); + builder.Services + .AddAuthentication(Core.Constants.Security.BackOfficeAuthenticationType) + .AddCookie(Core.Constants.Security.BackOfficeAuthenticationType) + .AddCookie(Core.Constants.Security.BackOfficeExternalAuthenticationType, o => + { + o.Cookie.Name = Core.Constants.Security.BackOfficeExternalAuthenticationType; + o.ExpireTimeSpan = TimeSpan.FromMinutes(5); + }); - public static IUmbracoBuilder WithBackOfficeIdentity(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithBackOfficeIdentity), () => builder.Services.AddUmbracoBackOfficeIdentity()); + // TODO: Need to add more cookie options, see https://github.com/dotnet/aspnetcore/blob/3.0/src/Identity/Core/src/IdentityServiceCollectionExtensions.cs#L45 - public static IUmbracoBuilder WithPreview(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithPreview), () => builder.Services.AddUmbracoPreview()); + builder.Services.ConfigureOptions(); + return builder; + } + + public static IUmbracoBuilder AddBackOfficeIdentity(this IUmbracoBuilder builder) + { + builder.Services.AddUmbracoBackOfficeIdentity(); + + return builder; + } + + public static IUmbracoBuilder AddPreviewSupport(this IUmbracoBuilder builder) + { + builder.Services.AddSignalR(); + + return builder; + } } } diff --git a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs index bc72b1dd44..600ff101fe 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/WebMappingProfiles.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; using Umbraco.Core.BackOffice; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Mapping; using Umbraco.Web.BackOffice.Mapping; @@ -9,16 +10,16 @@ namespace Umbraco.Extensions { public static class WebMappingProfiles { - public static Composition ComposeWebMappingProfiles(this Composition composition) + public static IUmbracoBuilder ComposeWebMappingProfiles(this IUmbracoBuilder builder) { - composition.WithCollectionBuilder() + builder.WithCollectionBuilder() .Add() .Add() .Add(); - composition.Services.AddTransient(); + builder.Services.AddTransient(); - return composition; + return builder; } } } diff --git a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs index 54e7006bec..a2ad2cd834 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; @@ -34,6 +35,7 @@ namespace Umbraco.Web.BackOffice.Mapping private readonly ILoggerFactory _loggerFactory; private readonly IUserService _userService; private readonly IEntityService _entityService; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IVariationContextAccessor _variationContextAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly UriUtility _uriUtility; @@ -43,9 +45,25 @@ namespace Umbraco.Web.BackOffice.Mapping private readonly ContentVariantMapper _contentVariantMapper; - public ContentMapDefinition(CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, ICultureDictionary cultureDictionary, ILocalizedTextService localizedTextService, IContentService contentService, IContentTypeService contentTypeService, - IFileService fileService, IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, ILocalizationService localizationService, ILoggerFactory loggerFactory, - IUserService userService, IVariationContextAccessor variationContextAccessor, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider, IEntityService entityService) + public ContentMapDefinition( + CommonMapper commonMapper, + CommonTreeNodeMapper commonTreeNodeMapper, + ICultureDictionary cultureDictionary, + ILocalizedTextService localizedTextService, + IContentService contentService, + IContentTypeService contentTypeService, + IFileService fileService, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedRouter publishedRouter, + ILocalizationService localizationService, + ILoggerFactory loggerFactory, + IUserService userService, + IVariationContextAccessor variationContextAccessor, + IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, + UriUtility uriUtility, + IPublishedUrlProvider publishedUrlProvider, + IEntityService entityService, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor) { _commonMapper = commonMapper; _commonTreeNodeMapper = commonTreeNodeMapper; @@ -60,6 +78,7 @@ namespace Umbraco.Web.BackOffice.Mapping _loggerFactory = loggerFactory; _userService = userService; _entityService = entityService; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _variationContextAccessor = variationContextAccessor; _uriUtility = uriUtility; _publishedUrlProvider = publishedUrlProvider; @@ -159,10 +178,10 @@ namespace Umbraco.Web.BackOffice.Mapping private IEnumerable GetActions(IContent source) { - var umbracoContext = _umbracoContextAccessor.UmbracoContext; + var backOfficeSecurity = _backOfficeSecurityAccessor.BackOfficeSecurity; //cannot check permissions without a context - if (umbracoContext == null) + if (backOfficeSecurity is null) return Enumerable.Empty(); string path; @@ -174,10 +193,7 @@ namespace Umbraco.Web.BackOffice.Mapping path = parent == null ? "-1" : parent.Path; } - // TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is - // with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null - // reference exception :( - return _userService.GetPermissionsForPath(umbracoContext.Security.CurrentUser, path).GetAllPermissions(); + return _userService.GetPermissionsForPath(backOfficeSecurity.CurrentUser, path).GetAllPermissions(); } private UrlInfo[] GetUrls(IContent source) diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs index fb6b015520..d11dffb1ac 100644 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -22,36 +23,36 @@ namespace Umbraco.Web.BackOffice.Runtime [ComposeAfter(typeof(AspNetCoreComposer))] public class BackOfficeComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddScoped(); - composition.Services.AddScoped(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + 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 = composition.TypeLoader.GetUmbracoApiControllers().ToList(); - composition.Trees() + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.Trees() .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); - composition.ComposeWebMappingProfiles(); + builder.ComposeWebMappingProfiles(); - composition.Services.AddUnique(factory => + builder.Services.AddUnique(factory => new PhysicalFileSystem( factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService>(), "~/")); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs index de40340e6f..e994571c90 100644 --- a/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs @@ -1,13 +1,14 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Web.BackOffice.SignalR { public class PreviewHubComposer : ComponentComposer, ICoreComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); } } } diff --git a/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs b/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs new file mode 100644 index 0000000000..9162c85cdd --- /dev/null +++ b/src/Umbraco.Web.Common/AspNetCore/OptionsMonitorAdapter.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.Extensions.Options; + +namespace Umbraco.Web.Common.AspNetCore +{ + /// + /// HACK: OptionsMonitor but without the monitoring, hopefully temporary. + /// This is just used so we can get an AspNetCoreHostingEnvironment to + /// build a TypeLoader long before ServiceProvider is built. + /// + [Obsolete("Please let the container wire up a real OptionsMonitor for you")] + internal class OptionsMonitorAdapter : IOptionsMonitor where T : class, new() + { + private readonly T _inner; + + public OptionsMonitorAdapter(T inner) + { + _inner = inner ?? throw new ArgumentNullException(nameof(inner)); + } + + public T Get(string name) + { + return _inner; + } + + public IDisposable OnChange(Action listener) + { + throw new NotImplementedException(); + } + + public T CurrentValue => _inner; + } +} diff --git a/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs b/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs deleted file mode 100644 index 2de7d2d285..0000000000 --- a/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Text; - -namespace Umbraco.Web.Common.Builder -{ - - public interface IUmbracoBuilder - { - IServiceCollection Services { get; } - IWebHostEnvironment WebHostEnvironment { get; } - IConfiguration Config { get; } - IUmbracoBuilder AddWith(string key, Action add); - void Build(); - } -} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs deleted file mode 100644 index 3efb1e74f5..0000000000 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; - -namespace Umbraco.Web.Common.Builder -{ - public class UmbracoBuilder : IUmbracoBuilder - { - private readonly Dictionary _registrations = new Dictionary(); - - public UmbracoBuilder(IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration config) - { - Services = services; - WebHostEnvironment = webHostEnvironment; - Config = config; - } - - public IServiceCollection Services { get; } - public IWebHostEnvironment WebHostEnvironment { get; } - public IConfiguration Config { get; } - - public IUmbracoBuilder AddWith(string key, Action add) - { - if (_registrations.ContainsKey(key)) return this; - _registrations[key] = add; - return this; - } - - public void Build() - { - foreach (var a in _registrations) - a.Value(); - } - } -} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 10f214a522..4c464ad989 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -5,85 +5,346 @@ using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data.SqlClient; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Serilog; +using Smidge; +using Smidge.Nuglify; using Umbraco.Core; +using Umbraco.Core.Builder; +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.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Runtime; using Umbraco.Extensions; +using Umbraco.Infrastructure.HostedServices; +using Umbraco.Infrastructure.HostedServices.ServerRegistration; +using Umbraco.Infrastructure.Runtime; +using Umbraco.Web.Common.ApplicationModels; +using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.ModelBinders; +using Umbraco.Web.Common.Profiler; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Web.Common.Builder { // TODO: We could add parameters to configure each of these for flexibility public static class UmbracoBuilderExtensions { - public static IUmbracoBuilder AddUmbraco(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration config) + public static IUmbracoBuilder AddUmbraco( + this IServiceCollection services, + IWebHostEnvironment webHostEnvironment, + IConfiguration config) { if (services is null) throw new ArgumentNullException(nameof(services)); - if (webHostEnvironment is null) throw new ArgumentNullException(nameof(webHostEnvironment)); if (config is null) throw new ArgumentNullException(nameof(config)); - services.AddLazySupport(); + var loggingConfig = new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); - var builder = new UmbracoBuilder(services, webHostEnvironment, config); + var tempHostingEnvironment = GetTemporaryHostingEnvironment(webHostEnvironment, config); + services.AddLogger(tempHostingEnvironment, loggingConfig, config); + + IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); + services.AddSingleton(httpContextAccessor); + + var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); + var appCaches = AppCaches.Create(requestCache); + services.AddUnique(appCaches); + + var profiler = GetWebProfiler(config); + services.AddUnique(profiler); + + var loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); + var typeLoader = services.AddTypeLoader(Assembly.GetEntryAssembly(), webHostEnvironment, tempHostingEnvironment, loggerFactory, appCaches, config, profiler); + + return new UmbracoBuilder(services, config, typeLoader, loggerFactory); + } + + /// Composes Composers + public static IUmbracoBuilder AddUmbracoCore(this IUmbracoBuilder builder) + { + if (builder is null) throw new ArgumentNullException(nameof(builder)); + + builder.Services.AddLazySupport(); + + // Add supported databases + builder.AddUmbracoSqlCeSupport(); + builder.AddUmbracoSqlServerSupport(); + + builder.Services.AddSingleton(factory => new DbProviderFactoryCreator( + DbProviderFactories.GetFactory, + factory.GetServices(), + factory.GetServices(), + 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(); + 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.AddComposers(); + return builder; } - public static IUmbracoBuilder WithConfiguration(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithConfiguration), () => builder.Services.AddUmbracoConfiguration(builder.Config)); + public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder) + { + var composerTypes = builder.TypeLoader.GetTypes(); + var enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); + new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger()).Compose(); - public static IUmbracoBuilder WithCore(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithCore), () => builder.Services.AddUmbracoCore(builder.WebHostEnvironment, builder.Config)); + return builder; + } - public static IUmbracoBuilder WithHostedServices(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithHostedServices), () => builder.Services.AddUmbracoHostedServices()); + 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>(); - public static IUmbracoBuilder WithHttpClients(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithHttpClients), () => builder.Services.AddUmbracoHttpClients()); + // 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)); - public static IUmbracoBuilder WithMiniProfiler(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithMiniProfiler), () => + return builder; + } + + + public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder) + { + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + return builder; + } + + public static IUmbracoBuilder AddHttpClients(this IUmbracoBuilder builder) + { + builder.Services.AddHttpClient(); + return builder; + } + + public static IUmbracoBuilder AddMiniProfiler(this IUmbracoBuilder builder) + { builder.Services.AddMiniProfiler(options => { options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile - })); - - public static IUmbracoBuilder WithMvcAndRazor(this IUmbracoBuilder builder, Action mvcOptions = null, Action mvcBuilding = null) - => builder.AddWith(nameof(WithMvcAndRazor), () => - { - - - // 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. - var mvcBuilder = builder.Services.AddControllersWithViews(options => - { - options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); - - options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); - mvcOptions?.Invoke(options); - }).AddRazorRuntimeCompilation(); - mvcBuilding?.Invoke(mvcBuilder); }); - public static IUmbracoBuilder WithRuntimeMinifier(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithRuntimeMinifier), () => builder.Services.AddUmbracoRuntimeMinifier(builder.Config)); + return builder; + } - public static IUmbracoBuilder WithWebComponents(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithWebComponents), () => builder.Services.AddUmbracoWebComponents(builder.Config)); - - public static IUmbracoBuilder WithWebServer(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithWebServer), () => + public static IUmbracoBuilder AddMvcAndRazor(this IUmbracoBuilder builder, Action mvcOptions = null, Action mvcBuilding = null) + { + // 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. + var mvcBuilder = builder.Services.AddControllersWithViews(options => { - // TODO: We need to figure out why thsi is needed and fix those endpoints to not need them, we don't want to change global things - // If using Kestrel: https://stackoverflow.com/a/55196057 - builder.Services.Configure(options => - { - options.AllowSynchronousIO = true; - }); - builder.Services.Configure(options => - { - options.AllowSynchronousIO = true; - }); + options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + + options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); + mvcOptions?.Invoke(options); + }).AddRazorRuntimeCompilation(); + mvcBuilding?.Invoke(mvcBuilder); + + return builder; + } + + public static IUmbracoBuilder AddRuntimeMinifier(this IUmbracoBuilder builder) + { + builder.Services.AddSmidge(builder.Config.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification)); + builder.Services.AddSmidgeNuglify(); + + return builder; + } + + public static IUmbracoBuilder AddWebComponents(this IUmbracoBuilder builder) + { + // Add service session + // This can be overwritten by the user by adding their own call to AddSession + // since the last call of AddSession take precedence + builder.Services.AddSession(options => + { + options.Cookie.Name = "UMB_SESSION"; + options.Cookie.HttpOnly = true; }); + + builder.Services.ConfigureOptions(); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); + builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); + builder.Services.AddUmbracoImageSharp(builder.Config); + + return builder; + } + + public static IUmbracoBuilder AddWebServer(this IUmbracoBuilder builder) + { + // TODO: We need to figure out why thsi is needed and fix those endpoints to not need them, we don't want to change global things + // If using Kestrel: https://stackoverflow.com/a/55196057 + builder.Services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + builder.Services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + + return builder; + } + + /// + /// Adds SqlCe support for Umbraco + /// + private static IUmbracoBuilder AddUmbracoSqlCeSupport(this IUmbracoBuilder builder) + { + try + { + var binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + if (binFolder != null) + { + var dllPath = Path.Combine(binFolder, "Umbraco.Persistance.SqlCe.dll"); + var umbSqlCeAssembly = Assembly.LoadFrom(dllPath); + + var sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeSyntaxProvider"); + var sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeBulkSqlInsertProvider"); + var sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeEmbeddedDatabaseCreator"); + + if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null || sqlCeEmbeddedDatabaseCreatorType is null)) + { + builder.Services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); + builder.Services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); + builder.Services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); + } + + var sqlCeAssembly = Assembly.LoadFrom(Path.Combine(binFolder, "System.Data.SqlServerCe.dll")); + + var sqlCe = sqlCeAssembly.GetType("System.Data.SqlServerCe.SqlCeProviderFactory"); + if (!(sqlCe is null)) + { + DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe); + } + } + } + catch + { + // Ignore if SqlCE is not available + } + + return builder; + } + + /// + /// Adds Sql Server support for Umbraco + /// + private static IUmbracoBuilder AddUmbracoSqlServerSupport(this IUmbracoBuilder builder) + { + DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); + + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + + return builder; + } + + private static IProfiler GetWebProfiler(IConfiguration config) + { + var isDebug = config.GetValue($"{Core.Constants.Configuration.ConfigHosting}:Debug"); + // create and start asap to profile boot + if (!isDebug) + { + // 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(); + } + + var webProfiler = new WebProfiler(); + webProfiler.StartBoot(); + + return webProfiler; + } + + /// + /// HACK: returns an AspNetCoreHostingEnvironment that doesn't monitor changes to configuration.
+ /// We require this to create a TypeLoader during ConfigureServices.
+ /// Instances returned from this method shouldn't be registered in the service collection. + ///
+ private static IHostingEnvironment GetTemporaryHostingEnvironment(IWebHostEnvironment webHostEnvironment, IConfiguration config) + { + var hostingSettings = config.GetSection(Core.Constants.Configuration.ConfigHosting).Get() ?? new HostingSettings(); + var wrappedHostingSettings = new OptionsMonitorAdapter(hostingSettings); + + return new AspNetCoreHostingEnvironment(wrappedHostingSettings, webHostEnvironment); + } } } diff --git a/src/Umbraco.Web.Common/Controllers/IRenderController.cs b/src/Umbraco.Web.Common/Controllers/IRenderController.cs index 3eaf1c35c3..7534abc9b4 100644 --- a/src/Umbraco.Web.Common/Controllers/IRenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/IRenderController.cs @@ -3,7 +3,6 @@ /// /// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking /// - /// Migrated already to .Net Core public interface IRenderController { diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index 36d4ddbd42..596c42e3b3 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -42,6 +42,9 @@ namespace Umbraco.Extensions if (!app.UmbracoCanBoot()) return app; + var hostingEnvironment = app.ApplicationServices.GetRequiredService(); + AppDomain.CurrentDomain.SetData("DataDirectory", hostingEnvironment?.MapPathContentRoot(Core.Constants.SystemDirectories.Data)); + var runtime = app.ApplicationServices.GetRequiredService(); // Register a listener for application shutdown in order to terminate the runtime diff --git a/src/Umbraco.Web/GridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/GridTemplateExtensions.cs similarity index 78% rename from src/Umbraco.Web/GridTemplateExtensions.cs rename to src/Umbraco.Web.Common/Extensions/GridTemplateExtensions.cs index 81dc33d2c6..e4a1c0d117 100644 --- a/src/Umbraco.Web/GridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/GridTemplateExtensions.cs @@ -1,27 +1,27 @@ using System; -using System.Web.Mvc; -using System.Web.Mvc.Html; +using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.Rendering; using Umbraco.Core.Models.PublishedContent; -namespace Umbraco.Web +namespace Umbraco.Extensions { public static class GridTemplateExtensions { - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedProperty property, string framework = "bootstrap3") + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedProperty property, string framework = "bootstrap3") { var asString = property.GetValue() as string; - if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty); var view = "Grid/" + framework; return html.Partial(view, property.GetValue()); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedContent contentItem) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedContent contentItem) { return html.GetGridHtml(contentItem, "bodyText", "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -29,7 +29,7 @@ namespace Umbraco.Web return html.GetGridHtml(contentItem, propertyAlias, "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias, string framework) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedContent contentItem, string propertyAlias, string framework) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -40,17 +40,17 @@ namespace Umbraco.Web var model = prop.GetValue(); var asString = model as string; - if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty); return html.Partial(view, model); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedElement contentItem) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedElement contentItem) { return html.GetGridHtml(contentItem, "bodyText", "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedElement contentItem, string propertyAlias) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedElement contentItem, string propertyAlias) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -58,7 +58,7 @@ namespace Umbraco.Web return html.GetGridHtml(contentItem, propertyAlias, "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedElement contentItem, string propertyAlias, string framework) + public static IHtmlContent GetGridHtml(this IHtmlHelper html, IPublishedElement contentItem, string propertyAlias, string framework) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -69,25 +69,25 @@ namespace Umbraco.Web var model = prop.GetValue(); var asString = model as string; - if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty); return html.Partial(view, model); } - public static MvcHtmlString GetGridHtml(this IPublishedProperty property, HtmlHelper html, string framework = "bootstrap3") + public static IHtmlContent GetGridHtml(this IPublishedProperty property, IHtmlHelper html, string framework = "bootstrap3") { var asString = property.GetValue() as string; - if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty); var view = "Grid/" + framework; return html.Partial(view, property.GetValue()); } - public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem, HtmlHelper html) + public static IHtmlContent GetGridHtml(this IPublishedContent contentItem, IHtmlHelper html) { return GetGridHtml(contentItem, html, "bodyText", "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem, HtmlHelper html, string propertyAlias) + public static IHtmlContent GetGridHtml(this IPublishedContent contentItem, IHtmlHelper html, string propertyAlias) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -95,7 +95,7 @@ namespace Umbraco.Web return GetGridHtml(contentItem, html, propertyAlias, "bootstrap3"); } - public static MvcHtmlString GetGridHtml(this IPublishedContent contentItem, HtmlHelper html, string propertyAlias, string framework) + public static IHtmlContent GetGridHtml(this IPublishedContent contentItem, IHtmlHelper html, string propertyAlias, string framework) { if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias)); if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias)); @@ -106,7 +106,7 @@ namespace Umbraco.Web var model = prop.GetValue(); var asString = model as string; - if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty); + if (asString != null && string.IsNullOrEmpty(asString)) return new HtmlString(string.Empty); return html.Partial(view, model); } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index 348cccb9f1..f42fc274f0 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -1,11 +1,6 @@ -using System; -using System.Data.Common; -using System.Data.SqlClient; using System.IO; using System.Reflection; -using System.Runtime.InteropServices; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -15,379 +10,24 @@ using Serilog.Extensions.Hosting; 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.IO; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; -using Umbraco.Infrastructure.HostedServices; -using Umbraco.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.Common.Profiler; -using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; -using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Extensions { public static class UmbracoCoreServiceCollectionExtensions { - /// - /// Adds the Umbraco Configuration requirements - /// - /// - /// - /// - public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services, IConfiguration configuration) - { - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - - // Register configuration validators. - services.AddSingleton, ContentSettingsValidator>(); - services.AddSingleton, GlobalSettingsValidator>(); - services.AddSingleton, HealthChecksSettingsValidator >(); - services.AddSingleton, RequestHandlerSettingsValidator>(); - - // Register configuration sections. - services.Configure(configuration.GetSection(Constants.Configuration.ConfigActiveDirectory)); - services.Configure(configuration.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigContent)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigCoreDebug)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigExceptionFilter)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigGlobal)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigHealthChecks)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigHosting)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigImaging)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigExamine)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigKeepAlive)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigLogging)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigMemberPassword)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigNuCache)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigRequestHandler)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigRuntime)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigSecurity)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigTours)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigTypeFinder)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigUserPassword)); - services.Configure(configuration.GetSection(Constants.Configuration.ConfigWebRouting)); - - return services; - } - - /// - /// Adds the Umbraco Back Core requirements - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddUmbracoCore(this IServiceCollection services, - IWebHostEnvironment webHostEnvironment, - Assembly entryAssembly, - AppCaches appCaches, - ILoggingConfiguration loggingConfiguration, - IConfiguration configuration) - => services.AddUmbracoCore(webHostEnvironment, entryAssembly, appCaches, loggingConfiguration, configuration, GetCoreRuntime); - - /// - /// Adds the Umbraco Back Core requirements - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration configuration) - { - var loggingConfig = new LoggingConfiguration( - Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); - - IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); - services.AddSingleton(httpContextAccessor); - services.AddSingleton(loggingConfig); - - var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); - var appCaches = new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache()), - requestCache, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); - - services.AddUmbracoCore(webHostEnvironment, - Assembly.GetEntryAssembly(), - appCaches, - loggingConfig, - configuration, - GetCoreRuntime); - - return services; - } - - /// - /// Adds the Umbraco Back Core requirements - /// - /// - /// - /// - /// - /// - /// - /// - /// Delegate to create an - /// - /// - public static IServiceCollection AddUmbracoCore( - this IServiceCollection services, - IWebHostEnvironment webHostEnvironment, - Assembly entryAssembly, - AppCaches appCaches, - ILoggingConfiguration loggingConfiguration, - IConfiguration configuration, - //TODO: Yep that's extremely ugly - Func getRuntimeBootstrapper) - { - if (services is null) throw new ArgumentNullException(nameof(services)); - if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly)); - - services.AddLazySupport(); - - // Add service session - // This can be overwritten by the user by adding their own call to AddSession - // since the last call of AddSession take precedence - services.AddSession(options => - { - options.Cookie.Name = "UMB_SESSION"; - options.Cookie.HttpOnly = true; - }); - - // Add supported databases - services.AddUmbracoSqlCeSupport(); - services.AddUmbracoSqlServerSupport(); - - services.AddSingleton(x => new DbProviderFactoryCreator( - DbProviderFactories.GetFactory, - x.GetServices(), - x.GetServices(), - x.GetServices() - )); - - // TODO: We want to avoid pre-resolving a container as much as possible we should not - // be doing this any more than we are now. The ugly part about this is that the service - // instances resolved here won't be the same instances resolved from the container - // later once the true container is built. However! ... in the case of IDbProviderFactoryCreator - // it will be the same instance resolved later because we are re-registering this instance back - // into the container. This is not true for `Configs` but we should do that too, see comments in - // `RegisterEssentials`. - var serviceProvider = services.BuildServiceProvider(); - - var globalSettings = serviceProvider.GetService>(); - var connectionStrings = serviceProvider.GetService>(); - var hostingSettings = serviceProvider.GetService>(); - var typeFinderSettings = serviceProvider.GetService>(); - - var dbProviderFactoryCreator = serviceProvider.GetRequiredService(); - - CreateCompositionRoot(services, - globalSettings, - hostingSettings, - webHostEnvironment, - loggingConfiguration, - configuration, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler); - - var loggerFactory = services.BuildServiceProvider().GetService(); - - var umbracoVersion = new UmbracoVersion(); - var typeFinder = CreateTypeFinder(loggerFactory, profiler, webHostEnvironment, entryAssembly, typeFinderSettings); - - var bootstrapper = getRuntimeBootstrapper( - globalSettings.CurrentValue, - connectionStrings.Value, - umbracoVersion, - ioHelper, - loggerFactory, - profiler, - hostingEnvironment, - backOfficeInfo, - typeFinder, - appCaches, - dbProviderFactoryCreator); - - bootstrapper.Configure(services); - - return services; - } - - /// - /// Adds SqlCe support for Umbraco - /// - /// - /// - private static IServiceCollection AddUmbracoSqlCeSupport(this IServiceCollection services) - { - try - { - var binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - if (binFolder != null) - { - var dllPath = Path.Combine(binFolder, "Umbraco.Persistance.SqlCe.dll"); - var umbSqlCeAssembly = Assembly.LoadFrom(dllPath); - - var sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeSyntaxProvider"); - var sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeBulkSqlInsertProvider"); - var sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Persistance.SqlCe.SqlCeEmbeddedDatabaseCreator"); - - if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null || sqlCeEmbeddedDatabaseCreatorType is null)) - { - services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); - services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); - services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); - } - - var sqlCeAssembly = Assembly.LoadFrom(Path.Combine(binFolder, "System.Data.SqlServerCe.dll")); - - var sqlCe = sqlCeAssembly.GetType("System.Data.SqlServerCe.SqlCeProviderFactory"); - if (!(sqlCe is null)) - { - DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe); - } - } - } - catch - { - // Ignore if SqlCE is not available - } - - return services; - } - - /// - /// Adds Sql Server support for Umbraco - /// - /// - /// - public static IServiceCollection AddUmbracoSqlServerSupport(this IServiceCollection services) - { - DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - return services; - } - - /// - /// Adds hosted services for Umbraco. - /// - /// - /// - public static IServiceCollection AddUmbracoHostedServices(this IServiceCollection services) - { - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - services.AddHostedService(); - - services.AddHostedService(); - services.AddHostedService(); - - return services; - } - - /// - /// Adds HTTP clients for Umbraco. - /// - /// - /// - public static IServiceCollection AddUmbracoHttpClients(this IServiceCollection services) - { - services.AddHttpClient(); - return services; - } - - private static ITypeFinder CreateTypeFinder(ILoggerFactory loggerFactory, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IOptionsMonitor typeFinderSettings) - { - var runtimeHashPaths = new RuntimeHashPaths(); - runtimeHashPaths.AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); - var runtimeHash = new RuntimeHash(new ProfilingLogger(loggerFactory.CreateLogger("RuntimeHash"), profiler), runtimeHashPaths); - return new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash, new TypeFinderConfig(typeFinderSettings)); - } - - private static CoreRuntimeBootstrapper GetCoreRuntime( - GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILoggerFactory loggerFactory, - IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, - ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator) - { - // Determine if we should use the sql main dom or the default - var appSettingMainDomLock = globalSettings.MainDomLock; - - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbProviderFactoryCreator, hostingEnvironment) - : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); - - var mainDom = new MainDom(loggerFactory.CreateLogger(), mainDomLock); - - var coreRuntime = new CoreRuntimeBootstrapper( - globalSettings, - connectionStrings, - umbracoVersion, - ioHelper, - loggerFactory, - profiler, - new AspNetCoreBootPermissionsChecker(), - hostingEnvironment, - backOfficeInfo, - dbProviderFactoryCreator, - mainDom, - typeFinder, - appCaches); - - return coreRuntime; - } - - private static IServiceCollection CreateCompositionRoot( - IServiceCollection services, - IOptionsMonitor globalSettings, - IOptionsMonitor hostingSettings, - IWebHostEnvironment webHostEnvironment, - ILoggingConfiguration loggingConfiguration, - IConfiguration configuration, - out IIOHelper ioHelper, - out Core.Hosting.IHostingEnvironment hostingEnvironment, - out IBackOfficeInfo backOfficeInfo, - out IProfiler profiler) - { - if (globalSettings == null) - throw new InvalidOperationException($"Could not resolve type {typeof(GlobalSettings)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}"); - - hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment); - ioHelper = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? new IOHelperLinux(hostingEnvironment) - : (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? (IIOHelper)new IOHelperOSX(hostingEnvironment) : new IOHelperWindows(hostingEnvironment)); - AddLogger(services, hostingEnvironment, loggingConfiguration, configuration); - backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings); - profiler = GetWebProfiler(hostingEnvironment); - - return services; - } /// /// Create and configure the logger /// - /// - private static void AddLogger( - IServiceCollection services, + public static IServiceCollection AddLogger( + this IServiceCollection services, IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration, IConfiguration configuration) @@ -398,7 +38,6 @@ namespace Umbraco.Extensions // This is nessasary to pick up all the loggins to MS ILogger. Log.Logger = logger.SerilogLog; - // Wire up all the bits that serilog needs. We need to use our own code since the Serilog ext methods don't cater to our needs since // we don't want to use the global serilog `Log` object and we don't have our own ILogger implementation before the HostBuilder runs which // is the only other option that these ext methods allow. @@ -421,32 +60,61 @@ namespace Umbraco.Extensions // Consumed by user code services.AddSingleton(diagnosticContext); + services.AddSingleton(loggingConfiguration); + + return services; } - private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment) + internal static ITypeFinder AddTypeFinder( + this IServiceCollection services, + ILoggerFactory loggerFactory, + IWebHostEnvironment webHostEnvironment, + Assembly entryAssembly, + IConfiguration config, + IProfilingLogger profilingLogger) { - // create and start asap to profile boot - if (!hostingEnvironment.IsDebugMode) - { - // 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(); - } - var webProfiler = new WebProfiler(); - webProfiler.StartBoot(); + var typeFinderSettings = config.GetSection(Core.Constants.Configuration.ConfigTypeFinder).Get() ?? new TypeFinderSettings(); - return webProfiler; + var runtimeHashPaths = new RuntimeHashPaths().AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); + var runtimeHash = new RuntimeHash(profilingLogger, runtimeHashPaths); + + var typeFinder = new TypeFinder( + loggerFactory.CreateLogger(), + new DefaultUmbracoAssemblyProvider(entryAssembly), + runtimeHash, + new TypeFinderConfig(Options.Create(typeFinderSettings)) + ); + + services.AddUnique(typeFinder); + + return typeFinder; } - private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker + public static TypeLoader AddTypeLoader( + this IServiceCollection services, + Assembly entryAssembly, + IWebHostEnvironment webHostEnvironment, + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory, + AppCaches appCaches, + IConfiguration configuration, + IProfiler profiler) { - public void ThrowIfNotPermissions() - { - // nothing to check - } - } + var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger(), profiler); + var typeFinder = services.AddTypeFinder(loggerFactory, webHostEnvironment, entryAssembly, configuration, profilingLogger); + var typeLoader = new TypeLoader( + typeFinder, + appCaches.RuntimeCache, + new DirectoryInfo(hostingEnvironment.LocalTempPath), + loggerFactory.CreateLogger(), + profilingLogger + ); + + services.AddUnique(typeLoader); + + return typeLoader; + } } - } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs index fdab7d7169..c1f9849621 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs @@ -14,28 +14,17 @@ using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; using Smidge; using Smidge.Nuglify; +using Umbraco.Core.Builder; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; using Umbraco.Web.Common.ApplicationModels; namespace Umbraco.Extensions { public static class UmbracoWebServiceCollectionExtensions { - /// - /// Registers the web components needed for Umbraco - /// - /// - /// - /// - public static IServiceCollection AddUmbracoWebComponents(this IServiceCollection services, IConfiguration configuration) - { - services.ConfigureOptions(); - services.TryAddEnumerable(ServiceDescriptor.Transient()); - services.TryAddEnumerable(ServiceDescriptor.Transient()); - services.AddUmbracoImageSharp(configuration); + - return services; - } /// /// Adds Image Sharp with Umbraco settings @@ -81,20 +70,6 @@ namespace Umbraco.Extensions return services; } - /// - /// Adds the Umbraco runtime minifier - /// - /// - /// - /// - public static IServiceCollection AddUmbracoRuntimeMinifier(this IServiceCollection services, - IConfiguration configuration) - { - services.AddSmidge(configuration.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification)); - services.AddSmidgeNuglify(); - - return services; - } private static void RemoveIntParamenterIfValueGreatherThen(IDictionary commands, string parameter, int maxValue) { @@ -117,7 +92,7 @@ namespace Umbraco.Extensions /// We generally don't want to change the global MVC settings since we want to be unobtrusive as possible but some /// global mods are needed - so long as they don't interfere with normal user usages of MVC. /// - private class UmbracoMvcConfigureOptions : IConfigureOptions + public class UmbracoMvcConfigureOptions : IConfigureOptions { // TODO: we can inject params with DI here diff --git a/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs index 05d46b431a..0c30b25ced 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Common.Filters /// internal static bool Enable = true; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoContextAccessor _umbracoContext; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IRuntimeState _runtimeState; private readonly LinkGenerator _linkGenerator; private readonly bool _redirectToUmbracoLogin; @@ -31,12 +31,13 @@ namespace Umbraco.Web.Common.Filters private UmbracoBackOfficeAuthorizeFilter( IHostingEnvironment hostingEnvironment, - IUmbracoContextAccessor umbracoContext, - IRuntimeState runtimeState, LinkGenerator linkGenerator, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, + IRuntimeState runtimeState, + LinkGenerator linkGenerator, bool redirectToUmbracoLogin, bool requireApproval, string redirectUrl) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); - _umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); _linkGenerator = linkGenerator ?? throw new ArgumentNullException(nameof(linkGenerator)); _redirectToUmbracoLogin = redirectToUmbracoLogin; @@ -54,17 +55,17 @@ namespace Umbraco.Web.Common.Filters /// public UmbracoBackOfficeAuthorizeFilter( IHostingEnvironment hostingEnvironment, - IUmbracoContextAccessor umbracoContext, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IRuntimeState runtimeState, LinkGenerator linkGenerator, - string redirectUrl) : this(hostingEnvironment, umbracoContext, runtimeState, linkGenerator, false, false, redirectUrl) + string redirectUrl) : this(hostingEnvironment, backOfficeSecurityAccessor, runtimeState, linkGenerator, false, false, redirectUrl) { } public UmbracoBackOfficeAuthorizeFilter( IHostingEnvironment hostingEnvironment, - IUmbracoContextAccessor umbracoContext, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IRuntimeState runtimeState, LinkGenerator linkGenerator, - bool redirectToUmbracoLogin, bool requireApproval) : this(hostingEnvironment, umbracoContext, runtimeState, linkGenerator, redirectToUmbracoLogin, requireApproval, null) + bool redirectToUmbracoLogin, bool requireApproval) : this(hostingEnvironment, backOfficeSecurityAccessor, runtimeState, linkGenerator, redirectToUmbracoLogin, requireApproval, null) { } @@ -99,7 +100,7 @@ namespace Umbraco.Web.Common.Filters // otherwise we need to ensure that a user is logged in return _runtimeState.Level == RuntimeLevel.Install || _runtimeState.Level == RuntimeLevel.Upgrade - || _umbracoContext.UmbracoContext?.Security.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; + || _backOfficeSecurityAccessor?.BackOfficeSecurity.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; } catch (Exception) { diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index 27c2922637..4019f462eb 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using System.Collections.Generic; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Extensions; namespace Umbraco.Web.Common.Filters @@ -12,6 +13,13 @@ namespace Umbraco.Web.Common.Filters ///
public class UmbracoMemberAuthorizeFilter : IAuthorizationFilter { + private readonly IUmbracoWebsiteSecurity _websiteSecurity; + + public UmbracoMemberAuthorizeFilter(IUmbracoWebsiteSecurity websiteSecurity) + { + _websiteSecurity = websiteSecurity; + } + /// /// Comma delimited list of allowed member types /// @@ -27,9 +35,7 @@ namespace Umbraco.Web.Common.Filters /// public string AllowMembers { get; private set; } - - private UmbracoMemberAuthorizeFilter( - string allowType, string allowGroup, string allowMembers) + private UmbracoMemberAuthorizeFilter(string allowType, string allowGroup, string allowMembers) { AllowType = allowType; AllowGroup = allowGroup; @@ -48,11 +54,19 @@ namespace Umbraco.Web.Common.Filters private bool IsAuthorized() { if (AllowMembers.IsNullOrWhiteSpace()) - AllowMembers = ""; + { + AllowMembers = string.Empty; + } + if (AllowGroup.IsNullOrWhiteSpace()) - AllowGroup = ""; + { + AllowGroup = string.Empty; + } + if (AllowType.IsNullOrWhiteSpace()) - AllowType = ""; + { + AllowType = string.Empty; + } var members = new List(); foreach (var s in AllowMembers.Split(',')) @@ -63,7 +77,7 @@ namespace Umbraco.Web.Common.Filters } } - return false;// TODO reintroduce when members are implemented: _memberHelper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); + return _websiteSecurity.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); } } } diff --git a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs index 6ccebc9b25..bddb4fd015 100644 --- a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs +++ b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs @@ -1,9 +1,9 @@ using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Core; +using Umbraco.Core.Security; namespace Umbraco.Web.Common.Install { @@ -19,33 +19,42 @@ namespace Umbraco.Web.Common.Install private class InstallAuthorizeFilter : IAuthorizationFilter { + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + private readonly IRuntimeState _runtimeState; + private readonly ILogger _logger; + + public InstallAuthorizeFilter( + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, + IRuntimeState runtimeState, + ILogger logger) + { + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + _runtimeState = runtimeState; + _logger = logger; + } + public void OnAuthorization(AuthorizationFilterContext authorizationFilterContext) { - var serviceProvider = authorizationFilterContext.HttpContext.RequestServices; - var runtimeState = serviceProvider.GetService(); - var umbracoContext = serviceProvider.GetService(); - var logger = serviceProvider.GetService>(); - - if (!IsAllowed(runtimeState, umbracoContext, logger)) + if (!IsAllowed()) { authorizationFilterContext.Result = new ForbidResult(); } } - private static bool IsAllowed(IRuntimeState runtimeState, IUmbracoContext umbracoContext, ILogger logger) + private bool IsAllowed() { try { // if not configured (install or upgrade) then we can continue // otherwise we need to ensure that a user is logged in - return runtimeState.Level == RuntimeLevel.Install - || runtimeState.Level == RuntimeLevel.Upgrade - || (umbracoContext?.Security?.ValidateCurrentUser() ?? false); + return _runtimeState.Level == RuntimeLevel.Install + || _runtimeState.Level == RuntimeLevel.Upgrade + || (_backOfficeSecurityAccessor?.BackOfficeSecurity?.ValidateCurrentUser() ?? false); } catch (Exception ex) { - logger.LogError(ex, "An error occurred determining authorization"); + _logger.LogError(ex, "An error occurred determining authorization"); return false; } } diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index 448a216e40..c79c5229fc 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -25,6 +25,7 @@ namespace Umbraco.Web.Macros private readonly IProfilingLogger _profilingLogger; private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly ContentSettings _contentSettings; private readonly ILocalizedTextService _textService; private readonly AppCaches _appCaches; @@ -40,6 +41,7 @@ namespace Umbraco.Web.Macros IProfilingLogger profilingLogger , ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IOptions contentSettings, ILocalizedTextService textService, AppCaches appCaches, @@ -54,6 +56,7 @@ namespace Umbraco.Web.Macros _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger )); _logger = logger; _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _textService = textService; _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); @@ -89,7 +92,7 @@ namespace Umbraco.Web.Macros { object key = 0; - if (_umbracoContextAccessor.GetRequiredUmbracoContext().Security.IsAuthenticated()) + if (_backOfficeSecurityAccessor.BackOfficeSecurity.IsAuthenticated()) { key = _memberUserKeyProvider.GetMemberProviderUserKey() ?? 0; } diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs index fd8f275291..702c30f692 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs @@ -1,15 +1,16 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; namespace Umbraco.Web.Common.Profiler { internal class WebProfilerComposer : ComponentComposer, ICoreComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs index 196b115618..58fa5ea317 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreBootFailedComposer.cs @@ -1,4 +1,5 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Web.Common.Middleware; @@ -9,9 +10,9 @@ namespace Umbraco.Web.Common.Runtime /// public class AspNetCoreBootFailedComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Services.AddUnique(); + builder.Services.AddUnique(); } } } diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 8acea23289..d5980c10b5 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Diagnostics; @@ -40,62 +41,64 @@ namespace Umbraco.Web.Common.Runtime [ComposeAfter(typeof(CoreInitialComposer))] public class AspNetCoreComposer : ComponentComposer, IComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); // AspNetCore specific services - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); // Our own netcore implementations - composition.Services.AddMultipleUnique(); + builder.Services.AddMultipleUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); // The umbraco request lifetime - composition.Services.AddMultipleUnique(); + builder.Services.AddMultipleUnique(); // Password hasher - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddTransient(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddTransient(); + builder.Services.AddUnique(); - composition.Services.AddMultipleUnique(); + builder.Services.AddMultipleUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); // register the umbraco context factory - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); //register the install components - composition.ComposeInstaller(); + builder.ComposeInstaller(); - var umbracoApiControllerTypes = composition.TypeLoader.GetUmbracoApiControllers().ToList(); - composition.WithCollectionBuilder() + var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); + builder.WithCollectionBuilder() .Add(umbracoApiControllerTypes); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddUnique(factory => new LegacyPasswordSecurity()); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(factory => new LegacyPasswordSecurity()); } } } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs index 3400ee49d9..5b3d776679 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Smidge.FileProcessors; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Runtime; using Umbraco.Core.WebAssets; @@ -9,14 +10,14 @@ namespace Umbraco.Web.Common.RuntimeMinification { public sealed class SmidgeComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { // TODO: For this to work we need to have services.AddSmidge() based on the Smidge APIs but our composer APIs don't really let us do that // This makes it a bit awkward to boot the runtime since that call would need to be made outside of the composer... .hrm... - composition.Services.AddUnique(); - composition.Services.AddUnique(); - composition.Services.AddTransient(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddTransient(); } } } diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index a0bc8b9140..56dd4b054e 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -21,6 +21,7 @@ namespace Umbraco.Web private readonly Lazy _publishedSnapshot; private string _previewToken; private bool? _previewing; + private IBackOfficeSecurity _backofficeSecurity; // initializes a new instance of the UmbracoContext class // internal for unit tests @@ -46,7 +47,7 @@ namespace Umbraco.Web ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); + _backofficeSecurity = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); @@ -74,11 +75,6 @@ namespace Umbraco.Web /// public Guid UmbracoRequestId { get; } - /// - /// Gets the BackofficeSecurity class - /// - public IBackOfficeSecurity Security { get; } - /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. /// @@ -168,7 +164,7 @@ namespace Umbraco.Web var requestUrl = _requestAccessor.GetRequestUrl(); if (requestUrl != null && requestUrl.IsBackOfficeRequest(_globalSettings, _hostingEnvironment) == false - && Security.CurrentUser != null) + && _backofficeSecurity.CurrentUser != null) { var previewToken = _cookieManager.GetCookieValue(Constants.Web.PreviewCookieName); // may be null or empty _previewToken = previewToken.IsNullOrWhiteSpace() ? null : previewToken; @@ -190,8 +186,6 @@ namespace Umbraco.Web { // DisposableObject ensures that this runs only once - Security.DisposeIfDisposable(); - // help caches release resources // (but don't create caches just to dispose them) // context is not multi-threaded diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs index 2a4d4a4580..ca62523c4d 100644 --- a/src/Umbraco.Web.UI.NetCore/Startup.cs +++ b/src/Umbraco.Web.UI.NetCore/Startup.cs @@ -32,12 +32,10 @@ namespace Umbraco.Web.UI.NetCore // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - var umbracoBuilder = services.AddUmbraco(_env, _config); - umbracoBuilder - .WithAllBackOfficeComponents() - .WithAllWebsiteComponents() + services.AddUmbraco(_env, _config) + .AddAllBackOfficeComponents() + .AddUmbracoWebsite() .Build(); - } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj index 6cc92f18da..9bd49b2999 100644 --- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj +++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj @@ -59,15 +59,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/Umbraco.Web.UI/Views/Partials/BlockList/Default.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/BlockList/Default.cshtml similarity index 77% rename from src/Umbraco.Web.UI/Views/Partials/BlockList/Default.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/BlockList/Default.cshtml index c94a51f6d9..6da7e63ac6 100644 --- a/src/Umbraco.Web.UI/Views/Partials/BlockList/Default.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/BlockList/Default.cshtml @@ -1,13 +1,13 @@ -@inherits UmbracoViewPage -@using Umbraco.Core.Models.Blocks -@{ - if (!Model.Any()) { return; } -} -
- @foreach (var block in Model) - { - if (block?.ContentUdi == null) { continue; } - var data = block.Content; - @Html.Partial("BlockList/Components/" + data.ContentType.Alias, block) - } -
+@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage +@using Umbraco.Core.Models.Blocks +@{ + if (!Model.Any()) { return; } +} +
+ @foreach (var block in Model) + { + if (block?.ContentUdi == null) { continue; } + var data = block.Content; + @Html.Partial("BlockList/Components/" + data.ContentType.Alias, block) + } +
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3-Fluid.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3-Fluid.cshtml similarity index 66% rename from src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3-Fluid.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3-Fluid.cshtml index 131b0515ae..b8bb0b521e 100644 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3-Fluid.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3-Fluid.cshtml @@ -1,5 +1,6 @@ -@inherits UmbracoViewPage -@using Umbraco.Web.Templates +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage +@using System.Web +@using Microsoft.AspNetCore.Html @using Newtonsoft.Json.Linq @* @@ -36,25 +37,28 @@ } -@helper renderRow(dynamic row){ -
-
- @foreach ( var area in row.areas ) { -
-
- @foreach (var control in area.controls) { - if (control !=null && control.editor != null && control.editor.view != null ) { - @Html.Partial("grid/editors/base", (object)control) - } - } -
-
} +@functions { + private void renderRow(dynamic row) + { +
+
+ @foreach ( var area in row.areas ) { +
+
+ @foreach (var control in area.controls) { + if (control !=null && control.editor != null && control.editor.view != null ) { + @Html.Partial("grid/editors/base", (object)control) + } + } +
+
} +
-
+ } } @functions { - public static MvcHtmlString RenderElementAttributes(dynamic contentItem) + public static HtmlString RenderElementAttributes(dynamic contentItem) { var attrs = new List(); JObject cfg = contentItem.config; @@ -83,6 +87,6 @@ attrs.Add("style='" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "'"); } - return new MvcHtmlString(string.Join(" ", attrs)); + return new HtmlString(string.Join(" ", attrs)); } } diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3.cshtml similarity index 63% rename from src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3.cshtml index c30feb2165..5453a7aac5 100644 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Bootstrap3.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Bootstrap3.cshtml @@ -1,5 +1,6 @@ -@inherits UmbracoViewPage -@using Umbraco.Web.Templates +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage +@using System.Web +@using Microsoft.AspNetCore.Html @using Newtonsoft.Json.Linq @if (Model != null && Model.sections != null) @@ -34,31 +35,37 @@
} -@helper renderRow(dynamic row, bool singleColumn){ -
- @if (singleColumn) { - @:
- } -
- @foreach ( var area in row.areas ) { -
-
- @foreach (var control in area.controls) { - if (control !=null && control.editor != null && control.editor.view != null ) { - @Html.Partial("grid/editors/base", (object)control) - } - } -
-
} +@functions { + + private void renderRow(dynamic row, bool singleColumn) + { +
+ @if (singleColumn) { + @:
+ } +
+ @foreach ( var area in row.areas ) { +
+
+ @foreach (var control in area.controls) { + if (control !=null && control.editor != null && control.editor.view != null ) { + @Html.Partial("grid/editors/base", (object)control) + } + } +
+
} +
+ @if (singleColumn) { + @:
+ }
- @if (singleColumn) { - @:
- } -
+ } + } + @functions { - public static MvcHtmlString RenderElementAttributes(dynamic contentItem) + public static HtmlString RenderElementAttributes(dynamic contentItem) { var attrs = new List(); JObject cfg = contentItem.config; @@ -87,6 +94,6 @@ attrs.Add("style=\"" + HttpUtility.HtmlAttributeEncode(string.Join(" ", cssVals)) + "\""); } - return new MvcHtmlString(string.Join(" ", attrs)); + return new HtmlString(string.Join(" ", attrs)); } } diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Base.cshtml similarity index 75% rename from src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Base.cshtml index a86c04819a..d3cdf80f06 100644 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Base.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Base.cshtml @@ -1,12 +1,11 @@ @model dynamic -@using Umbraco.Web.Templates @functions { public static string EditorView(dynamic contentItem) { string view = contentItem.editor.render != null ? contentItem.editor.render.ToString() : contentItem.editor.view.ToString(); view = view.ToLower().Replace(".html", ".cshtml"); - + if (!view.Contains("/")) { view = "grid/editors/" + view; } @@ -16,9 +15,9 @@ } @try { - string editor = EditorView(Model); + string editor = EditorView(Model); @Html.Partial(editor, (object)Model) } -catch (Exception ex) { +catch (Exception ex) {
@ex.ToString()
-} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Embed.cshtml similarity index 80% rename from src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Embed.cshtml index 4a915a444b..250310217c 100644 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Embed.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Embed.cshtml @@ -1,5 +1,6 @@ -@model dynamic -@using Umbraco.Web.Templates +@using Umbraco.Core +@model dynamic + @{ string embedValue = Convert.ToString(Model.value); embedValue = embedValue.DetectIsJson() ? Model.value.preview : Model.value; diff --git a/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Macro.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Macro.cshtml new file mode 100644 index 0000000000..26c6e8a09c --- /dev/null +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Macro.cshtml @@ -0,0 +1,17 @@ +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage +@using Umbraco.Web.Website +@inject UmbracoHelper Umbraco; + +@if (Model.value != null) +{ + string macroAlias = Model.value.macroAlias.ToString(); + var parameters = new Dictionary(); + foreach (var mpd in Model.value.macroParamsDictionary) + { + parameters.Add(mpd.Name, mpd.Value); + } + + + @Umbraco.RenderMacro(macroAlias, parameters) + +} diff --git a/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Rte.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Rte.cshtml new file mode 100644 index 0000000000..b7bac31bd1 --- /dev/null +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/Rte.cshtml @@ -0,0 +1,13 @@ +@model dynamic +@using Umbraco.Web.Templates +@inject HtmlLocalLinkParser HtmlLocalLinkParser; +@inject HtmlUrlParser HtmlUrlParser; +@inject HtmlImageSourceParser HtmlImageSourceParser; + +@{ + + var value = HtmlUrlParser.EnsureUrls(Model.value.ToString()); + value = HtmlImageSourceParser.EnsureImageSources(value); + value = HtmlLocalLinkParser.EnsureInternalLinks(value); +} +@Html.Raw(value) diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml similarity index 87% rename from src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml rename to src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml index 0e47b5bd78..2ceac54e26 100644 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/TextString.cshtml +++ b/src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml @@ -1,6 +1,6 @@ -@model dynamic -@using Umbraco.Web.Composing -@using Umbraco.Web.Templates +@using System.Web +@using Umbraco.Extensions +@model dynamic @if (Model.editor.config.markup != null) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/EditProfile.cshtml similarity index 83% rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml rename to src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/EditProfile.cshtml index 576541ea4a..de5f3167b0 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/EditProfile.cshtml @@ -1,14 +1,13 @@ -@using System.Web.Mvc.Html -@using Umbraco.Web -@using Umbraco.Web.Composing -@using Umbraco.Web.Controllers -@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using Umbraco.Core.Security +@using Umbraco.Extensions +@using Umbraco.Web.Website.Controllers +@inherits Umbraco.Web.Common.Macros.PartialViewMacroPage +@inject IUmbracoWebsiteSecurityAccessor UmbracoWebsiteSecurityAccessor @{ - var profileModel = Current.MembershipHelper.GetCurrentMemberProfileModel(); + var websiteSecurity = UmbracoWebsiteSecurityAccessor.WebsiteSecurity; + var profileModel = await websiteSecurity.GetCurrentMemberProfileModelAsync(); - Html.EnableClientValidation(); - Html.EnableUnobtrusiveJavaScript(); var success = TempData["ProfileUpdateSuccess"] != null; } @@ -17,7 +16,7 @@ -@if (Current.MembershipHelper.IsLoggedIn() && profileModel != null) +@if (websiteSecurity.IsLoggedIn() && profileModel != null) { if (success) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/Login.cshtml similarity index 75% rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml rename to src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/Login.cshtml index b50d1ac806..bd4c9e1e59 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/Login.cshtml @@ -1,17 +1,12 @@ -@using System.Web.Mvc.Html -@using Umbraco.Web -@using Umbraco.Web.Composing -@using Umbraco.Web.Models -@using Umbraco.Web.Controllers -@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using Microsoft.AspNetCore.Http.Extensions +@using Umbraco.Core.Models.Security +@using Umbraco.Extensions +@using Umbraco.Web.Website.Controllers +@inherits Umbraco.Web.Common.Macros.PartialViewMacroPage @{ var loginModel = new LoginModel(); - loginModel.RedirectUrl = HttpContext.Current.Request.Url.AbsolutePath; - - Html.EnableClientValidation(); - Html.EnableUnobtrusiveJavaScript(); - + loginModel.RedirectUrl = Context.Request.GetDisplayUrl(); } diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/LoginStatus.cshtml similarity index 60% rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml rename to src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/LoginStatus.cshtml index 78b06151af..72f5e814c8 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/LoginStatus.cshtml @@ -1,12 +1,13 @@ -@using System.Web.Mvc.Html -@using Umbraco.Web -@using Umbraco.Web.Composing -@using Umbraco.Web.Models -@using Umbraco.Web.Controllers -@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using Umbraco.Core.Security +@using Umbraco.Core.Models.Security +@using Umbraco.Extensions +@using Umbraco.Web.Website.Controllers +@inherits Umbraco.Web.Common.Macros.PartialViewMacroPage +@inject IUmbracoWebsiteSecurityAccessor UmbracoWebsiteSecurityAccessor @{ - var loginStatusModel = Current.MembershipHelper.GetCurrentLoginStatus(); + var websiteSecurity = UmbracoWebsiteSecurityAccessor.WebsiteSecurity; + var loginStatusModel = await websiteSecurity.GetCurrentLoginStatusAsync(); var logoutModel = new PostRedirectModel(); @* diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/RegisterMember.cshtml similarity index 91% rename from src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml rename to src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/RegisterMember.cshtml index 5e6230a294..0876e64b08 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/PartialViewMacros/Templates/RegisterMember.cshtml @@ -1,8 +1,8 @@ -@using System.Web.Mvc.Html -@using Umbraco.Web -@using Umbraco.Web.Composing -@using Umbraco.Web.Controllers -@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using Umbraco.Core.Security +@using Umbraco.Extensions +@using Umbraco.Web.Website.Controllers +@inherits Umbraco.Web.Common.Macros.PartialViewMacroPage +@inject IUmbracoWebsiteSecurityAccessor UmbracoWebsiteSecurityAccessor @{ @* @@ -12,7 +12,8 @@ var registerModel = Members.CreateRegistrationModel("Custom Member"); *@ - var registerModel = Current.MembershipHelper.CreateRegistrationModel(); + var websiteSecurity = UmbracoWebsiteSecurityAccessor.WebsiteSecurity; + var registerModel = websiteSecurity.CreateRegistrationModel(); @* Configurable here: @@ -31,9 +32,6 @@ @Html.ValidationMessageFor(m => registerModel.Username) *@ - Html.EnableClientValidation(); - Html.EnableUnobtrusiveJavaScript(); - var success = TempData["FormSuccess"] != null; } diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 93f13e73e0..c2482fb934 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -78,9 +78,7 @@ - - - + @@ -178,36 +176,12 @@ Designer - - true - PreserveNewest - - - true - PreserveNewest - - - true - PreserveNewest - - - true - PreserveNewest - Designer Designer - - - - - - - - Web.Template.config Designer @@ -257,21 +231,8 @@ False True - 9000 - / - http://localhost:9000/ - http://localhost:8700 - 8610 - / - http://localhost:8610 - http://localhost:8700 - 8800 - 8900 8910 / - http://localhost:8800 - http://localhost:8700 - http://localhost:8900 http://localhost:8910 False False @@ -354,4 +315,4 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml deleted file mode 100644 index e0822808d8..0000000000 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Macro.cshtml +++ /dev/null @@ -1,17 +0,0 @@ -@inherits UmbracoViewPage -@using Umbraco.Web.Templates - - -@if (Model.value != null) -{ - string macroAlias = Model.value.macroAlias.ToString(); - ViewDataDictionary parameters = new ViewDataDictionary(); - foreach (dynamic mpd in Model.value.macroParamsDictionary) - { - parameters.Add(mpd.Name, mpd.Value); - } - - - @Umbraco.RenderMacro(macroAlias, parameters) - -} diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Rte.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Rte.cshtml deleted file mode 100644 index 715aad12d6..0000000000 --- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Rte.cshtml +++ /dev/null @@ -1,20 +0,0 @@ -@model dynamic -@using Umbraco.Web.Composing -@using Umbraco.Web.Templates - -@* - TODO: When this project is asp.net core we can @inject HtmlLocalLinkParser etc (or come up with something even better) -*@ - -@using Microsoft.Extensions.DependencyInjection - -@{ - var htmlLocalLinkParser = Current.Factory.GetRequiredService(); - var htmlUrlParser = Current.Factory.GetRequiredService(); - var htmlImageSourceParser = Current.Factory.GetRequiredService(); - - var value = htmlUrlParser.EnsureUrls(Model.value.ToString()); - value = htmlImageSourceParser.EnsureImageSources(value); - value = htmlLocalLinkParser.EnsureInternalLinks(value); -} -@Html.Raw(value) diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs index 8125923ee4..4e0517754c 100644 --- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs +++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs @@ -21,7 +21,13 @@ namespace Umbraco.Web.Website.Controllers // [MergeParentContextViewData] public abstract class SurfaceController : PluginController { - private readonly IPublishedUrlProvider _publishedUrlProvider; + protected SurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + { + PublishedUrlProvider = publishedUrlProvider; + } + + protected IPublishedUrlProvider PublishedUrlProvider { get; } /// /// Gets the current page. @@ -39,12 +45,6 @@ namespace Umbraco.Web.Website.Controllers } } - protected SurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _publishedUrlProvider = publishedUrlProvider; - } - /// /// Redirects to the Umbraco page with the given id /// @@ -52,7 +52,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey) { - return new RedirectToUmbracoPageResult(contentKey, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(contentKey, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -63,7 +63,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey, QueryString queryString) { - return new RedirectToUmbracoPageResult(contentKey, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(contentKey, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -73,7 +73,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent) { - return new RedirectToUmbracoPageResult(publishedContent, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(publishedContent, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -84,7 +84,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, QueryString queryString) { - return new RedirectToUmbracoPageResult(publishedContent, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(publishedContent, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -93,7 +93,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage() { - return new RedirectToUmbracoPageResult(CurrentPage, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(CurrentPage, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -103,7 +103,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(QueryString queryString) { - return new RedirectToUmbracoPageResult(CurrentPage, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(CurrentPage, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// diff --git a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs new file mode 100644 index 0000000000..6ba0f582c8 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs @@ -0,0 +1,60 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Persistence; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Website.Controllers +{ + public class UmbLoginController : SurfaceController + { + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; + + public UmbLoginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, + IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + { + _websiteSecurityAccessor = websiteSecurityAccessor; + } + + [HttpPost] + [ValidateAntiForgeryToken] + [ValidateUmbracoFormRouteString] + public async Task HandleLogin([Bind(Prefix = "loginModel")]LoginModel model) + { + if (ModelState.IsValid == false) + { + return CurrentUmbracoPage(); + } + + if (await _websiteSecurityAccessor.WebsiteSecurity.LoginAsync(model.Username, model.Password) == false) + { + // Don't add a field level error, just model level. + ModelState.AddModelError("loginModel", "Invalid username or password"); + return CurrentUmbracoPage(); + } + + TempData["LoginSuccess"] = true; + + // If there is a specified path to redirect to then use it. + if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + { + // Validate the redirect url. + // If it's not a local url we'll redirect to the root of the current site. + return Redirect(Url.IsLocalUrl(model.RedirectUrl) + ? model.RedirectUrl + : CurrentPage.AncestorOrSelf(1).Url(PublishedUrlProvider)); + } + + // Redirect to current page by default. + return RedirectToCurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs similarity index 50% rename from src/Umbraco.Web/Controllers/UmbLoginStatusController.cs rename to src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs index d7a8601838..e9bf164eb3 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs @@ -1,58 +1,54 @@ -using System.Web.Mvc; -using System.Web.Security; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.Security; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; -namespace Umbraco.Web.Controllers +namespace Umbraco.Web.Website.Controllers { - [MemberAuthorize] + [UmbracoMemberAuthorize] public class UmbLoginStatusController : SurfaceController { - private readonly MembershipHelper _membershipHelper; - - public UmbLoginStatusController() - { - } + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; public UmbLoginStatusController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, - IProfilingLogger profilingLogger, MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { - _membershipHelper = membershipHelper; + _websiteSecurityAccessor = websiteSecurityAccessor; } [HttpPost] [ValidateAntiForgeryToken] [ValidateUmbracoFormRouteString] - public ActionResult HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model) + public async Task HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model) { if (ModelState.IsValid == false) { return CurrentUmbracoPage(); } - if (_membershipHelper.IsLoggedIn()) + if (_websiteSecurityAccessor.WebsiteSecurity.IsLoggedIn()) { - FormsAuthentication.SignOut(); + await _websiteSecurityAccessor.WebsiteSecurity.LogOutAsync(); } TempData["LogoutSuccess"] = true; - //if there is a specified path to redirect to then use it + // If there is a specified path to redirect to then use it. if (model.RedirectUrl.IsNullOrWhiteSpace() == false) { return Redirect(model.RedirectUrl); } - //redirect to current page by default - + // Redirect to current page by default. return RedirectToCurrentUmbracoPage(); } } diff --git a/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs b/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs new file mode 100644 index 0000000000..cc23786c4b --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Persistence; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Website.Controllers +{ + [UmbracoMemberAuthorize] + public class UmbProfileController : SurfaceController + { + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; + + public UmbProfileController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, + IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + { + _websiteSecurityAccessor = websiteSecurityAccessor; + } + + [HttpPost] + [ValidateAntiForgeryToken] + [ValidateUmbracoFormRouteString] + public async Task HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model) + { + if (ModelState.IsValid == false) + { + return CurrentUmbracoPage(); + } + + var result = await _websiteSecurityAccessor.WebsiteSecurity.UpdateMemberProfileAsync(model); + switch (result.Status) + { + case UpdateMemberProfileStatus.Success: + break; + case UpdateMemberProfileStatus.Error: + // Don't add a field level error, just model level. + ModelState.AddModelError("profileModel", result.ErrorMessage); + return CurrentUmbracoPage(); + default: + throw new ArgumentOutOfRangeException(); + } + + TempData["ProfileUpdateSuccess"] = true; + + // If there is a specified path to redirect to then use it. + if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + { + return Redirect(model.RedirectUrl); + } + + // Redirect to current page by default. + return RedirectToCurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/UmbRegisterController.cs b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs similarity index 56% rename from src/Umbraco.Web/Controllers/UmbRegisterController.cs rename to src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs index 30720eb776..9542a2bf75 100644 --- a/src/Umbraco.Web/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs @@ -1,37 +1,34 @@ using System; -using System.Web.Mvc; -using System.Web.Security; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.Security; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; -namespace Umbraco.Web.Controllers +namespace Umbraco.Web.Website.Controllers { public class UmbRegisterController : SurfaceController { - private readonly MembershipHelper _membershipHelper; - - public UmbRegisterController() - { - } + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; public UmbRegisterController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, - IProfilingLogger profilingLogger, MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { - _membershipHelper = membershipHelper; + _websiteSecurityAccessor = websiteSecurityAccessor; } [HttpPost] [ValidateAntiForgeryToken] [ValidateUmbracoFormRouteString] - public ActionResult HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model) + public async Task HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model) { if (ModelState.IsValid == false) { @@ -39,60 +36,52 @@ namespace Umbraco.Web.Controllers } // U4-10762 Server error with "Register Member" snippet (Cannot save member with empty name) - // If name field is empty, add the email address instead + // If name field is empty, add the email address instead. if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false) { model.Name = model.Email; } - MembershipCreateStatus status; - var member = _membershipHelper.RegisterMember(model, out status, model.LoginOnSuccess); + var result = await _websiteSecurityAccessor.WebsiteSecurity.RegisterMemberAsync(model, model.LoginOnSuccess); - switch (status) + switch (result) { - case MembershipCreateStatus.Success: + case RegisterMemberStatus.Success: TempData["FormSuccess"] = true; - //if there is a specified path to redirect to then use it + // If there is a specified path to redirect to then use it. if (model.RedirectUrl.IsNullOrWhiteSpace() == false) { return Redirect(model.RedirectUrl); } - //redirect to current page by default + // Redirect to current page by default. return RedirectToCurrentUmbracoPage(); - case MembershipCreateStatus.InvalidUserName: + case RegisterMemberStatus.InvalidUserName: ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) ? "registerModel.Email" : "registerModel.Username", "Username is not valid"); break; - case MembershipCreateStatus.InvalidPassword: + case RegisterMemberStatus.InvalidPassword: ModelState.AddModelError("registerModel.Password", "The password is not strong enough"); break; - case MembershipCreateStatus.InvalidQuestion: - case MembershipCreateStatus.InvalidAnswer: - // TODO: Support q/a http://issues.umbraco.org/issue/U4-3213 - throw new NotImplementedException(status.ToString()); - case MembershipCreateStatus.InvalidEmail: + case RegisterMemberStatus.InvalidEmail: ModelState.AddModelError("registerModel.Email", "Email is invalid"); break; - case MembershipCreateStatus.DuplicateUserName: + case RegisterMemberStatus.DuplicateUserName: ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) ? "registerModel.Email" : "registerModel.Username", "A member with this username already exists."); break; - case MembershipCreateStatus.DuplicateEmail: + case RegisterMemberStatus.DuplicateEmail: ModelState.AddModelError("registerModel.Email", "A member with this e-mail address already exists"); break; - case MembershipCreateStatus.UserRejected: - case MembershipCreateStatus.InvalidProviderUserKey: - case MembershipCreateStatus.DuplicateProviderUserKey: - case MembershipCreateStatus.ProviderError: - //don't add a field level error, just model level - ModelState.AddModelError("registerModel", "An error occurred creating the member: " + status); + case RegisterMemberStatus.Error: + // Don't add a field level error, just model level. + ModelState.AddModelError("registerModel", $"An error occurred creating the member: {result}"); break; default: throw new ArgumentOutOfRangeException(); @@ -100,6 +89,5 @@ namespace Umbraco.Web.Controllers return CurrentUmbracoPage(); } - } } diff --git a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs index a48ed435bf..e56b136b9c 100644 --- a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; -using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; using Umbraco.Core.Cache; @@ -214,7 +213,7 @@ namespace Umbraco.Extensions // /// // /// // /// - // public static IHtmlContent Action(this HtmlHelper htmlHelper, string actionName) + // public static IHtmlContent Action(this IHtmlHelper htmlHelper, string actionName) // where T : SurfaceController // { // return htmlHelper.Action(actionName, typeof(T)); @@ -274,7 +273,6 @@ namespace Umbraco.Extensions /// /// /// - /// /// public UmbracoForm( ViewContext viewContext, @@ -282,19 +280,15 @@ namespace Umbraco.Extensions string controllerName, string controllerAction, string area, - FormMethod method, object additionalRouteVals = null) : base(viewContext, htmlEncoder) { _viewContext = viewContext; - _method = method; _controllerName = controllerName; _encryptedString = EncryptionHelper.CreateEncryptedRouteString(GetRequiredService(viewContext), controllerName, controllerAction, area, additionalRouteVals); } - private readonly ViewContext _viewContext; - private readonly FormMethod _method; private bool _disposed; private readonly string _encryptedString; private readonly string _controllerName; @@ -330,7 +324,7 @@ namespace Umbraco.Extensions /// Name of the controller. /// The method. /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, FormMethod method) { return html.BeginUmbracoForm(action, controllerName, null, new Dictionary(), method); } @@ -342,7 +336,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName) { return html.BeginUmbracoForm(action, controllerName, null, new Dictionary()); } @@ -356,7 +350,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, object additionalRouteVals, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals, FormMethod method) { return html.BeginUmbracoForm(action, controllerName, additionalRouteVals, new Dictionary(), method); } @@ -369,7 +363,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, object additionalRouteVals) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals) { return html.BeginUmbracoForm(action, controllerName, additionalRouteVals, new Dictionary()); } @@ -384,7 +378,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals, object htmlAttributes, FormMethod method) @@ -401,7 +395,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals, object htmlAttributes) { @@ -418,7 +412,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals, IDictionary htmlAttributes, FormMethod method) @@ -440,7 +434,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, object additionalRouteVals, IDictionary htmlAttributes) { @@ -460,7 +454,7 @@ namespace Umbraco.Extensions /// The surface controller to route to /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, FormMethod method) { return html.BeginUmbracoForm(action, surfaceType, null, new Dictionary(), method); } @@ -472,7 +466,7 @@ namespace Umbraco.Extensions /// /// The surface controller to route to /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType) { return html.BeginUmbracoForm(action, surfaceType, null, new Dictionary()); } @@ -485,7 +479,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, FormMethod method) where T : SurfaceController { return html.BeginUmbracoForm(action, typeof(T), method); @@ -498,7 +492,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action) where T : SurfaceController { return html.BeginUmbracoForm(action, typeof(T)); @@ -513,7 +507,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals, FormMethod method) { return html.BeginUmbracoForm(action, surfaceType, additionalRouteVals, new Dictionary(), method); @@ -527,7 +521,7 @@ namespace Umbraco.Extensions /// The surface controller to route to /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals) { return html.BeginUmbracoForm(action, surfaceType, additionalRouteVals, new Dictionary()); @@ -542,7 +536,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, object additionalRouteVals, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals, FormMethod method) where T : SurfaceController { return html.BeginUmbracoForm(action, typeof(T), additionalRouteVals, method); @@ -556,7 +550,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, object additionalRouteVals) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals) where T : SurfaceController { return html.BeginUmbracoForm(action, typeof(T), additionalRouteVals); @@ -572,7 +566,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals, object htmlAttributes, FormMethod method) @@ -589,7 +583,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals, object htmlAttributes) { @@ -606,7 +600,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals, object htmlAttributes, FormMethod method) @@ -624,7 +618,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals, object htmlAttributes) where T : SurfaceController @@ -642,7 +636,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals, IDictionary htmlAttributes, FormMethod method) @@ -652,18 +646,19 @@ namespace Umbraco.Extensions if (string.IsNullOrWhiteSpace(action)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(action)); if (surfaceType == null) throw new ArgumentNullException(nameof(surfaceType)); - var area = ""; - var surfaceControllerTypeCollection = GetRequiredService(html); var surfaceController = surfaceControllerTypeCollection.SingleOrDefault(x => x == surfaceType); if (surfaceController == null) throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName); var metaData = PluginController.GetMetadata(surfaceController); + + var area = string.Empty; if (metaData.AreaName.IsNullOrWhiteSpace() == false) { - //set the area to the plugin area + // Set the area to the plugin area area = metaData.AreaName; } + return html.BeginUmbracoForm(action, metaData.ControllerName, area, additionalRouteVals, htmlAttributes, method); } @@ -676,7 +671,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, Type surfaceType, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, Type surfaceType, object additionalRouteVals, IDictionary htmlAttributes) { @@ -693,7 +688,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals, IDictionary htmlAttributes, FormMethod method) @@ -711,7 +706,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, object additionalRouteVals, IDictionary htmlAttributes) where T : SurfaceController @@ -728,7 +723,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, string area, FormMethod method) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, string area, FormMethod method) { return html.BeginUmbracoForm(action, controllerName, area, null, new Dictionary(), method); } @@ -741,7 +736,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, string area) + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, string area) { return html.BeginUmbracoForm(action, controllerName, area, null, new Dictionary()); } @@ -757,7 +752,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, string area, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, string area, object additionalRouteVals, IDictionary htmlAttributes, FormMethod method) @@ -782,7 +777,7 @@ namespace Umbraco.Extensions /// /// /// - public static MvcForm BeginUmbracoForm(this HtmlHelper html, string action, string controllerName, string area, + public static MvcForm BeginUmbracoForm(this IHtmlHelper html, string action, string controllerName, string area, object additionalRouteVals, IDictionary htmlAttributes) { @@ -804,7 +799,7 @@ namespace Umbraco.Extensions /// /// This code is pretty much the same as the underlying MVC code that writes out the form /// - private static MvcForm RenderForm(this HtmlHelper htmlHelper, + private static MvcForm RenderForm(this IHtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary htmlAttributes, @@ -837,12 +832,13 @@ namespace Umbraco.Extensions var htmlEncoder = GetRequiredService(htmlHelper); //new UmbracoForm: - var theForm = new UmbracoForm(htmlHelper.ViewContext, htmlEncoder, surfaceController, surfaceAction, area, method, additionalRouteVals); + var theForm = new UmbracoForm(htmlHelper.ViewContext, htmlEncoder, surfaceController, surfaceAction, area, additionalRouteVals); if (traditionalJavascriptEnabled) { htmlHelper.ViewContext.FormContext.FormData["FormId"] = tagBuilder.Attributes["id"]; } + return theForm; } @@ -859,7 +855,7 @@ namespace Umbraco.Extensions /// /// The HTML encoded value. /// - public static IHtmlContent If(this HtmlHelper html, bool test, string valueIfTrue) + public static IHtmlContent If(this IHtmlHelper html, bool test, string valueIfTrue) { return If(html, test, valueIfTrue, string.Empty); } @@ -874,7 +870,7 @@ namespace Umbraco.Extensions /// /// The HTML encoded value. /// - public static IHtmlContent If(this HtmlHelper html, bool test, string valueIfTrue, string valueIfFalse) + public static IHtmlContent If(this IHtmlHelper html, bool test, string valueIfTrue, string valueIfFalse) { return new HtmlString(HttpUtility.HtmlEncode(test ? valueIfTrue : valueIfFalse)); } @@ -893,7 +889,7 @@ namespace Umbraco.Extensions /// /// The HTML encoded text with text line breaks replaced with HTML line breaks (<br />). /// - public static IHtmlContent ReplaceLineBreaks(this HtmlHelper helper, string text) + public static IHtmlContent ReplaceLineBreaks(this IHtmlHelper helper, string text) { return StringUtilities.ReplaceLineBreaks(text); } @@ -905,7 +901,7 @@ namespace Umbraco.Extensions /// /// The text to create a hash from /// Hash of the text string - public static string CreateHash(this HtmlHelper helper, string text) + public static string CreateHash(this IHtmlHelper helper, string text) { return text.GenerateHash(); } diff --git a/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs b/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs index c01bdf7804..cdaa40ef6a 100644 --- a/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs @@ -4,7 +4,6 @@ using Umbraco.Core.Composing; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Website.Controllers; - namespace Umbraco.Extensions { /// diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs index 8e56cd6dca..3715f5e37b 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoBuilderExtensions.cs @@ -1,20 +1,32 @@ -using Umbraco.Web.Common.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Umbraco.Core.Builder; +using Umbraco.Web.Common.Builder; +using Umbraco.Web.Website.ViewEngines; namespace Umbraco.Extensions { public static class UmbracoBuilderExtensions { - public static IUmbracoBuilder WithAllWebsiteComponents(this IUmbracoBuilder builder) + public static IUmbracoBuilder AddUmbracoWebsite(this IUmbracoBuilder builder) { - builder - .WithUmbracoWebsite(); + // 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>(); + builder.Services.AddSingleton(); + builder.Services.AddTransient, PluginMvcViewOptionsSetup>(); + builder.Services.AddSingleton(); + + // Wraps all existing view engines in a ProfilerViewEngine + builder.Services.AddTransient, ProfilingViewEngineWrapperMvcViewOptionsSetup>(); + + //TODO figure out if we need more to work on load balanced setups + builder.Services.AddDataProtection(); return builder; } - public static IUmbracoBuilder WithUmbracoWebsite(this IUmbracoBuilder builder) - => builder.AddWith(nameof(WithUmbracoWebsite), () => builder.Services.AddUmbracoWebsite()); - } } diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs deleted file mode 100644 index 317afedc7a..0000000000 --- a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Umbraco.Web.Website.ViewEngines; - -namespace Umbraco.Extensions -{ - public static class UmbracoWebstiteServiceCollectionExtensions - { - public static void AddUmbracoWebsite(this IServiceCollection services) - { - // Set the render & plugin view engines (Super complicated, but this allows us to use the IServiceCollection - // to inject dependencies into the viewEngines) - services.AddTransient, RenderMvcViewOptionsSetup>(); - services.AddSingleton(); - services.AddTransient, PluginMvcViewOptionsSetup>(); - services.AddSingleton(); - - // Wraps all existing view engines in a ProfilerViewEngine - services.AddTransient, ProfilingViewEngineWrapperMvcViewOptionsSetup>(); - - //TODO figure out if we need more to work on load balanced setups - services.AddDataProtection(); - } - } -} diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs index 055b146a51..ce3ff7271e 100644 --- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs +++ b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs @@ -1,4 +1,5 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Extensions; using Umbraco.Web.Website.Routing; @@ -12,12 +13,12 @@ namespace Umbraco.Web.Website.Runtime [ComposeAfter(typeof(AspNetCoreComposer))] public class WebsiteComposer : IComposer { - public void Compose(Composition composition) + public void Compose(IUmbracoBuilder builder) { - composition.Services.AddUnique(); + builder.Services.AddUnique(); - composition.WithCollectionBuilder() - .Add(composition.TypeLoader.GetSurfaceControllers()); + builder.WithCollectionBuilder() + .Add(builder.TypeLoader.GetSurfaceControllers()); } } } diff --git a/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs b/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs new file mode 100644 index 0000000000..d110cf9661 --- /dev/null +++ b/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Http; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Website.Security +{ + public class UmbracoWebsiteSecurity : IUmbracoWebsiteSecurity + { + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IMemberService _memberService; + private readonly IMemberTypeService _memberTypeService; + private readonly IShortStringHelper _shortStringHelper; + + public UmbracoWebsiteSecurity(IHttpContextAccessor httpContextAccessor, + IMemberService memberService, + IMemberTypeService memberTypeService, + IShortStringHelper shortStringHelper) + { + _httpContextAccessor = httpContextAccessor; + _memberService = memberService; + _memberTypeService = memberTypeService; + _shortStringHelper = shortStringHelper; + } + + /// + public RegisterModel CreateRegistrationModel(string memberTypeAlias = null) + { + var providedOrDefaultMemberTypeAlias = memberTypeAlias ?? Constants.Conventions.MemberTypes.DefaultAlias; + var memberType = _memberTypeService.Get(providedOrDefaultMemberTypeAlias); + if (memberType == null) + { + throw new InvalidOperationException($"Could not find a member type with alias: {providedOrDefaultMemberTypeAlias}."); + } + + var model = RegisterModel.CreateModel(); + model.MemberTypeAlias = providedOrDefaultMemberTypeAlias; + model.MemberProperties = GetMemberPropertiesViewModel(memberType); + return model; + } + + private List GetMemberPropertiesViewModel(IMemberType memberType, IMember member = null) + { + var viewProperties = new List(); + + var builtIns = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper).Select(x => x.Key).ToArray(); + + var propertyTypes = memberType.PropertyTypes + .Where(x => builtIns.Contains(x.Alias) == false && memberType.MemberCanEditProperty(x.Alias)) + .OrderBy(p => p.SortOrder); + + foreach (var prop in propertyTypes) + { + var value = string.Empty; + if (member != null) + { + var propValue = member.Properties[prop.Alias]; + if (propValue != null && propValue.GetValue() != null) + { + value = propValue.GetValue().ToString(); + } + } + + var viewProperty = new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = value + }; + + // TODO: Perhaps one day we'll ship with our own EditorTempates but for now developers + // can just render their own. + + ////This is a rudimentary check to see what data template we should render + //// if developers want to change the template they can do so dynamically in their views or controllers + //// for a given property. + ////These are the default built-in MVC template types: “Boolean”, “Decimal”, “EmailAddress”, “HiddenInput”, “HTML”, “Object”, “String”, “Text”, and “Url” + //// by default we'll render a text box since we've defined that metadata on the UmbracoProperty.Value property directly. + //if (prop.DataTypeId == new Guid(Constants.PropertyEditors.TrueFalse)) + //{ + // viewProperty.EditorTemplate = "UmbracoBoolean"; + //} + //else + //{ + // switch (prop.DataTypeDatabaseType) + // { + // case DataTypeDatabaseType.Integer: + // viewProperty.EditorTemplate = "Decimal"; + // break; + // case DataTypeDatabaseType.Ntext: + // viewProperty.EditorTemplate = "Text"; + // break; + // case DataTypeDatabaseType.Date: + // case DataTypeDatabaseType.Nvarchar: + // break; + // } + //} + + viewProperties.Add(viewProperty); + } + + return viewProperties; + } + + public Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true) + { + throw new System.NotImplementedException(); + } + + /// + public async Task GetCurrentMemberProfileModelAsync() + { + if (IsLoggedIn() == false) + { + return null; + } + + var member = GetCurrentPersistedMember(); + + // This shouldn't happen but will if the member is deleted in the back office while the member is trying + // to use the front-end! + if (member == null) + { + // Log them out since they've been removed + await LogOutAsync(); + + return null; + } + + var model = new ProfileModel + { + Name = member.Name, + MemberTypeAlias = member.ContentTypeAlias, + + // TODO: get ASP.NET Core Identity equiavlant of MemberShipUser in order to get common membership properties such as Email + // and UserName (see MembershipProviderExtensions.GetCurrentUserName()for legacy membership provider implementation). + + //Email = membershipUser.Email, + //UserName = membershipUser.UserName, + //Comment = membershipUser.Comment, + //IsApproved = membershipUser.IsApproved, + //IsLockedOut = membershipUser.IsLockedOut, + //LastLockoutDate = membershipUser.LastLockoutDate, + //CreationDate = membershipUser.CreationDate, + //LastLoginDate = membershipUser.LastLoginDate, + //LastActivityDate = membershipUser.LastActivityDate, + //LastPasswordChangedDate = membershipUser.LastPasswordChangedDate + }; + + var memberType = _memberTypeService.Get(member.ContentTypeId); + + model.MemberProperties = GetMemberPropertiesViewModel(memberType, member); + + return model; + } + + /// + public Task UpdateMemberProfileAsync(ProfileModel model) + { + throw new NotImplementedException(); + } + + /// + public bool IsLoggedIn() + { + var httpContext = _httpContextAccessor.HttpContext; + return httpContext?.User != null && httpContext.User.Identity.IsAuthenticated; + } + + /// + public async Task GetCurrentLoginStatusAsync() + { + var model = LoginStatusModel.CreateModel(); + + if (IsLoggedIn() == false) + { + model.IsLoggedIn = false; + return model; + } + + var member = GetCurrentPersistedMember(); + + // This shouldn't happen but will if the member is deleted in the back office while the member is trying + // to use the front-end! + if (member == null) + { + // Log them out since they've been removed. + await LogOutAsync(); + model.IsLoggedIn = false; + return model; + } + + model.Name = member.Name; + model.Username = member.Username; + model.Email = member.Email; + model.IsLoggedIn = true; + + return model; + } + + /// + /// Returns the currently logged in IMember object - this should never be exposed to the front-end since it's returning a business logic entity! + /// + /// + private IMember GetCurrentPersistedMember() + { + // TODO: get user name from ASP.NET Core Identity (see MembershipProviderExtensions.GetCurrentUserName() + // for legacy membership provider implementation). + var username = ""; + + // The result of this is cached by the MemberRepository + return _memberService.GetByUsername(username); + } + + /// + public Task LoginAsync(string username, string password) + { + throw new NotImplementedException(); + } + + /// + public async Task LogOutAsync() + { + await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + } + + /// + public bool IsMemberAuthorized(IEnumerable allowTypes = null, IEnumerable allowGroups = null, IEnumerable allowMembers = null) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index daba18d51b..55cfa3e44d 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index b1e13745d8..8f698db995 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -21,6 +21,7 @@ using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Runtime; using Umbraco.Core.Scoping; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; @@ -87,6 +88,9 @@ namespace Umbraco.Web.Composing public static IUmbracoContext UmbracoContext => UmbracoContextAccessor.UmbracoContext; + public static IBackOfficeSecurityAccessor BackOfficeSecurityAccessor + => Factory.GetRequiredService(); + public static UmbracoHelper UmbracoHelper => Factory.GetRequiredService(); public static IUmbracoComponentRenderer UmbracoComponentRenderer diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs deleted file mode 100644 index d96e21aa3d..0000000000 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Web.Actions; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Dashboards; -using Umbraco.Web.Editors; -using Umbraco.Web.HealthCheck; -using Umbraco.Web.Media.EmbedProviders; -using Umbraco.Web.Mvc; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Search; -using Umbraco.Web.Sections; -using Umbraco.Web.Tour; -using Umbraco.Web.Trees; -using Current = Umbraco.Web.Composing.Current; - -// the namespace here is intentional - although defined in Umbraco.Web assembly, -// this class should be visible when using Umbraco.Core.Components, alongside -// Umbraco.Core's own CompositionExtensions class - -// ReSharper disable once CheckNamespace -namespace Umbraco.Web -{ - /// - /// Provides extension methods to the class. - /// - public static class WebCompositionExtensions - { - [Obsolete("This extension method exists only to ease migration, please refactor")] - public static IServiceProvider CreateServiceProvider(this Composition composition) - { - composition.RegisterBuilders(); - return composition.Services.BuildServiceProvider(); - } - - #region Uniques - - /// - /// Sets the content last chance finder. - /// - /// The type of the content last chance finder. - /// The composition. - public static void SetContentLastChanceFinder(this Composition composition) - where T : class, IContentLastChanceFinder - { - composition.Services.AddUnique(); - } - - /// - /// Sets the content last chance finder. - /// - /// The composition. - /// A function creating a last chance finder. - public static void SetContentLastChanceFinder(this Composition composition, Func factory) - { - composition.Services.AddUnique(factory); - } - - /// - /// Sets the content last chance finder. - /// - /// The composition. - /// A last chance finder. - public static void SetContentLastChanceFinder(this Composition composition, IContentLastChanceFinder finder) - { - composition.Services.AddUnique(_ => finder); - } - - /// - /// Sets the site domain helper. - /// - /// The type of the site domain helper. - /// - public static void SetSiteDomainHelper(this Composition composition) - where T : class, ISiteDomainHelper - { - composition.Services.AddUnique(); - } - - /// - /// Sets the site domain helper. - /// - /// The composition. - /// A function creating a helper. - public static void SetSiteDomainHelper(this Composition composition, Func factory) - { - composition.Services.AddUnique(factory); - } - - /// - /// Sets the site domain helper. - /// - /// The composition. - /// A helper. - public static void SetSiteDomainHelper(this Composition composition, ISiteDomainHelper helper) - { - composition.Services.AddUnique(_ => helper); - } - - #endregion - } -} diff --git a/src/Umbraco.Web/Controllers/UmbLoginController.cs b/src/Umbraco.Web/Controllers/UmbLoginController.cs deleted file mode 100644 index 1f3faf7a43..0000000000 --- a/src/Umbraco.Web/Controllers/UmbLoginController.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Web.Mvc; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Controllers -{ - public class UmbLoginController : SurfaceController - { - private readonly MembershipHelper _membershipHelper; - - public UmbLoginController() - { - } - - public UmbLoginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, - MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _membershipHelper = membershipHelper; - } - - [HttpPost] - [ValidateAntiForgeryToken] - [ValidateUmbracoFormRouteString] - public ActionResult HandleLogin([Bind(Prefix = "loginModel")]LoginModel model) - { - if (ModelState.IsValid == false) - { - return CurrentUmbracoPage(); - } - - if (_membershipHelper.Login(model.Username, model.Password) == false) - { - //don't add a field level error, just model level - ModelState.AddModelError("loginModel", "Invalid username or password"); - return CurrentUmbracoPage(); - } - - TempData["LoginSuccess"] = true; - - //if there is a specified path to redirect to then use it - if (model.RedirectUrl.IsNullOrWhiteSpace() == false) - { - // validate the redirect url - // if it's not a local url we'll redirect to the root of the current site - return Redirect(Url.IsLocalUrl(model.RedirectUrl) - ? model.RedirectUrl - : CurrentPage.AncestorOrSelf(1).Url()); - } - - //redirect to current page by default - - return RedirectToCurrentUmbracoPage(); - } - } -} diff --git a/src/Umbraco.Web/Controllers/UmbProfileController.cs b/src/Umbraco.Web/Controllers/UmbProfileController.cs deleted file mode 100644 index 88edee26c8..0000000000 --- a/src/Umbraco.Web/Controllers/UmbProfileController.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Web.Mvc; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Core.Security; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Controllers -{ - [MemberAuthorize] - public class UmbProfileController : SurfaceController - { - private readonly MembershipHelper _membershipHelper; - - public UmbProfileController() - { } - - public UmbProfileController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, - MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _membershipHelper = membershipHelper; - } - - [HttpPost] - [ValidateAntiForgeryToken] - [ValidateUmbracoFormRouteString] - public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model) - { - if (ModelState.IsValid == false) - { - return CurrentUmbracoPage(); - } - - var updateAttempt = _membershipHelper.UpdateMemberProfile(model); - if (updateAttempt.Success == false) - { - //don't add a field level error, just model level - ModelState.AddModelError("profileModel", updateAttempt.Exception.Message); - return CurrentUmbracoPage(); - } - - TempData["ProfileUpdateSuccess"] = true; - - //if there is a specified path to redirect to then use it - if (model.RedirectUrl.IsNullOrWhiteSpace() == false) - { - return Redirect(model.RedirectUrl); - } - - //redirect to current page by default - return RedirectToCurrentUmbracoPage(); - } - } -} diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs index a9127aca17..8ada898c21 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Mvc private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IBackOfficeSecurity BackOfficeSecurity => _backOfficeSecurityAccessor.BackOfficeSecurity ?? Current.UmbracoContext.Security; + private IBackOfficeSecurity BackOfficeSecurity => _backOfficeSecurityAccessor.BackOfficeSecurity ?? Current.BackOfficeSecurityAccessor.BackOfficeSecurity; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 32e7835ffb..0d866363c4 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -3,6 +3,7 @@ using System.Web.Security; using Microsoft.AspNet.SignalR; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.Dictionary; using Umbraco.Core.Templates; @@ -23,36 +24,36 @@ namespace Umbraco.Web.Runtime [ComposeBefore(typeof(ICoreComposer))] public sealed class WebInitialComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); + base.Compose(builder); - composition.Services.AddTransient(); + builder.Services.AddTransient(); // register membership stuff - composition.Services.AddTransient(factory => MembershipProviderExtensions.GetMembersMembershipProvider()); - composition.Services.AddTransient(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetRequiredService())); - composition.Services.AddScoped(); - composition.Services.AddTransient(factory => factory.GetRequiredService().PublishedSnapshot.Members); - composition.Services.AddUnique(); - composition.Services.AddUnique(); + builder.Services.AddTransient(factory => MembershipProviderExtensions.GetMembersMembershipProvider()); + builder.Services.AddTransient(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetRequiredService())); + builder.Services.AddScoped(); + builder.Services.AddTransient(factory => factory.GetRequiredService().PublishedSnapshot.Members); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddTransient(factory => + { + var state = factory.GetRequiredService(); - // register the umbraco helper - this is Transient! very important! - // also, if not level.Run, we cannot really use the helper (during upgrade...) - // so inject a "void" helper (not exactly pretty but...) - if (composition.RuntimeState.Level == RuntimeLevel.Run) - composition.Services.AddTransient(factory => + if (state.Level == RuntimeLevel.Run) { var umbCtx = factory.GetRequiredService(); return new UmbracoHelper(umbCtx.IsFrontEndUmbracoRequest ? umbCtx.PublishedRequest?.PublishedContent : null, factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService()); - }); - else - composition.Services.AddTransient(_ => new UmbracoHelper()); + } - composition.Services.AddUnique(); + return new UmbracoHelper(); + }); + + builder.Services.AddUnique(); // configure the container for web //composition.ConfigureForWeb(); diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index 6d762afcd9..1e26782d4a 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -1,20 +1,20 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web.Security; using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Web.Models; -using Umbraco.Web.PublishedCache; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Models.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Editors; +using Umbraco.Web.Models; +using Umbraco.Web.PublishedCache; using Umbraco.Web.Security.Providers; -using System.ComponentModel.DataAnnotations; namespace Umbraco.Web.Security { @@ -443,7 +443,7 @@ namespace Umbraco.Web.Security return null; } - var model = ProfileModel.CreateModel(); + var model = new ProfileModel(); model.Name = member.Name; model.MemberTypeAlias = member.ContentTypeAlias; @@ -458,7 +458,6 @@ namespace Umbraco.Web.Security model.LastActivityDate = membershipUser.LastActivityDate; model.LastPasswordChangedDate = membershipUser.LastPasswordChangedDate; - var memberType = _memberTypeService.Get(member.ContentTypeId); var builtIns = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper).Select(x => x.Key).ToArray(); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b54df88855..1b4ec244d8 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -142,6 +142,7 @@ + @@ -183,7 +184,7 @@ - + @@ -220,9 +221,6 @@ - - - @@ -236,13 +234,9 @@ - - - - @@ -253,10 +247,8 @@ - - diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 3218710902..032ee9bb4f 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -19,35 +19,8 @@ namespace Umbraco.Web /// public class UmbracoApplication : UmbracoApplicationBase { - protected override CoreRuntimeBootstrapper GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, ILoggerFactory loggerFactory, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - { - var dbProviderFactoryCreator = new UmbracoDbProviderFactoryCreator(); - // Determine if we should use the sql main dom or the default - var appSettingMainDomLock = globalSettings.MainDomLock; - - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbProviderFactoryCreator, hostingEnvironment) - : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); - - var mainDom = new MainDom(loggerFactory.CreateLogger(), mainDomLock); - - // Commented out as part of .NET Core transition as the HttpRequestAppCache constructor has changed to - // to match the change in the type of the HTTP context Items collection. - //// var requestCache = new HttpRequestAppCache(() => HttpContext.Current != null ? HttpContext.Current.Items : null); - IRequestCache requestCache = null; - var appCaches = new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache()), - requestCache, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); - - var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker(); - return new CoreRuntimeBootstrapper(globalSettings, connectionStrings,umbracoVersion, ioHelper, loggerFactory, profiler, umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, - GetTypeFinder(hostingEnvironment, logger, profiler), appCaches); - } - } } diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index a04cea4fed..c7066c664f 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -113,7 +113,7 @@ namespace Umbraco.Web runtimeHashPaths.AddFile(new FileInfo(hostingEnvironment.MapPathContentRoot("~/App_Code"))); // global.asax (the app domain also monitors this, if it changes will do a full restart) runtimeHashPaths.AddFile(new FileInfo(hostingEnvironment.MapPathContentRoot("~/global.asax"))); - var runtimeHash = new RuntimeHash(new ProfilingLogger(_loggerFactory.CreateLogger("RuntimeHash"), profiler), runtimeHashPaths); + var runtimeHash = new RuntimeHash(new ProfilingLogger(_loggerFactory.CreateLogger(), profiler), runtimeHashPaths); return new TypeFinder(_loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider( // GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website // in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since @@ -129,11 +129,6 @@ namespace Umbraco.Web Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()), runtimeHash); } - /// - /// Gets a runtime. - /// - protected abstract CoreRuntimeBootstrapper GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, ILoggerFactory loggerFactory, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo); - /// /// Gets the application register. /// @@ -177,17 +172,17 @@ namespace Umbraco.Web // create the register for the application, and boot // the boot manager is responsible for registrations var register = GetRegister(globalSettings); - var boostrapper = GetRuntime( - _globalSettings, - _connectionStrings, - umbracoVersion, - _ioHelper, - _logger, - _loggerFactory, - null, // TODO get from somewhere that isn't Current. - null, // TODO get from somewhere that isn't Current. - null // TODO get from somewhere that isn't Current. - ); + //var boostrapper = GetRuntime( + // _globalSettings, + // _connectionStrings, + // umbracoVersion, + // _ioHelper, + // _logger, + // _loggerFactory, + // null, // TODO get from somewhere that isn't Current. + // null, // TODO get from somewhere that isn't Current. + // null // TODO get from somewhere that isn't Current. + // ); //_factory = Current.Factory = _runtime.Configure(register); diff --git a/src/Umbraco.Web/UmbracoBuilderExtensions.cs b/src/Umbraco.Web/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..422d0a8b23 --- /dev/null +++ b/src/Umbraco.Web/UmbracoBuilderExtensions.cs @@ -0,0 +1,87 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core; +using Umbraco.Core.Builder; +using Umbraco.Web.Routing; + +namespace Umbraco.Web +{ + /// + /// Provides extension methods to the class. + /// + public static class UmbracoBuilderExtensions + { + [Obsolete("This extension method exists only to ease migration, please refactor")] + public static IServiceProvider CreateServiceProvider(this IUmbracoBuilder builder) + { + builder.Build(); + return builder.Services.BuildServiceProvider(); + } + + #region Uniques + + /// + /// Sets the content last chance finder. + /// + /// The type of the content last chance finder. + /// The builder. + public static void SetContentLastChanceFinder(this IUmbracoBuilder builder) + where T : class, IContentLastChanceFinder + { + builder.Services.AddUnique(); + } + + /// + /// Sets the content last chance finder. + /// + /// The builder. + /// A function creating a last chance finder. + public static void SetContentLastChanceFinder(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the content last chance finder. + /// + /// The builder. + /// A last chance finder. + public static void SetContentLastChanceFinder(this IUmbracoBuilder builder, IContentLastChanceFinder finder) + { + builder.Services.AddUnique(finder); + } + + /// + /// Sets the site domain helper. + /// + /// The type of the site domain helper. + /// + public static void SetSiteDomainHelper(this IUmbracoBuilder builder) + where T : class, ISiteDomainHelper + { + builder.Services.AddUnique(); + } + + /// + /// Sets the site domain helper. + /// + /// The builder. + /// A function creating a helper. + public static void SetSiteDomainHelper(this IUmbracoBuilder builder, Func factory) + { + builder.Services.AddUnique(factory); + } + + /// + /// Sets the site domain helper. + /// + /// The builder. + /// A helper. + public static void SetSiteDomainHelper(this IUmbracoBuilder builder, ISiteDomainHelper helper) + { + builder.Services.AddUnique(helper); + } + + #endregion + } +} diff --git a/src/Umbraco.Web/UmbracoHttpHandler.cs b/src/Umbraco.Web/UmbracoHttpHandler.cs index 8a76770fda..711af68613 100644 --- a/src/Umbraco.Web/UmbracoHttpHandler.cs +++ b/src/Umbraco.Web/UmbracoHttpHandler.cs @@ -13,12 +13,13 @@ namespace Umbraco.Web private UrlHelper _url; protected UmbracoHttpHandler() - : this(Current.UmbracoContextAccessor, Current.Services, Current.Logger, Current.ProfilingLogger) + : this(Current.UmbracoContextAccessor, Current.BackOfficeSecurityAccessor, Current.Services, Current.Logger, Current.ProfilingLogger) { } - protected UmbracoHttpHandler(IUmbracoContextAccessor umbracoContextAccessor,ServiceContext service, ILogger logger, IProfilingLogger profilingLogger ) + protected UmbracoHttpHandler(IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor,ServiceContext service, ILogger logger, IProfilingLogger profilingLogger ) { UmbracoContextAccessor = umbracoContextAccessor; + BackOfficeSecurityAccessor = backOfficeSecurityAccessor; Logger = logger; ProfilingLogger = profilingLogger ; Services = service; @@ -43,6 +44,8 @@ namespace Umbraco.Web /// public IUmbracoContextAccessor UmbracoContextAccessor { get; } + public IBackOfficeSecurityAccessor BackOfficeSecurityAccessor { get; } + /// /// Gets the services context. /// @@ -51,7 +54,7 @@ namespace Umbraco.Web /// /// Gets the web security helper. /// - public IBackOfficeSecurity Security => UmbracoContextAccessor.UmbracoContext.Security; + public IBackOfficeSecurity Security => BackOfficeSecurityAccessor.BackOfficeSecurity; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/UmbracoWebService.cs b/src/Umbraco.Web/UmbracoWebService.cs index 0d4c4646f0..27c6af2c8b 100644 --- a/src/Umbraco.Web/UmbracoWebService.cs +++ b/src/Umbraco.Web/UmbracoWebService.cs @@ -16,17 +16,18 @@ namespace Umbraco.Web { private UrlHelper _url; - protected UmbracoWebService(ILogger logger, IProfilingLogger profilingLogger, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, GlobalSettings globalSettings) + protected UmbracoWebService(ILogger logger, IProfilingLogger profilingLogger, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ServiceContext services, GlobalSettings globalSettings) { Logger = logger; ProfilingLogger = profilingLogger; UmbracoContextAccessor = umbracoContextAccessor; + BackOfficeSecurityAccessor = backOfficeSecurityAccessor; Services = services; GlobalSettings = globalSettings; } protected UmbracoWebService() - : this(Current.Logger, Current.ProfilingLogger, Current.UmbracoContextAccessor, Current.Services, new GlobalSettings()) + : this(Current.Logger, Current.ProfilingLogger, Current.UmbracoContextAccessor, Current.BackOfficeSecurityAccessor, Current.Services,new GlobalSettings()) { } @@ -50,6 +51,8 @@ namespace Umbraco.Web /// public IUmbracoContextAccessor UmbracoContextAccessor { get; } + public IBackOfficeSecurityAccessor BackOfficeSecurityAccessor { get; } + /// /// Gets the services context. /// @@ -63,7 +66,7 @@ namespace Umbraco.Web /// /// Gets the web security helper. /// - public IBackOfficeSecurity Security => UmbracoContext.Security; + public IBackOfficeSecurity Security => BackOfficeSecurityAccessor.BackOfficeSecurity; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index 724ea810c9..b1d8c7fcfe 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Routing; @@ -21,8 +22,8 @@ namespace Umbraco.Web.WebApi { } - protected UmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) + protected UmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + : base(globalSettings, umbracoContextAccessor, backOfficeSecurityAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index 7d9c620a6d..e5e123db88 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -41,6 +41,7 @@ namespace Umbraco.Web.WebApi : this( Current.Factory.GetRequiredService(), Current.Factory.GetRequiredService(), + Current.Factory.GetRequiredService(), Current.Factory.GetRequiredService(), Current.Factory.GetRequiredService(), Current.Factory.GetRequiredService(), @@ -54,9 +55,10 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoApiControllerBase(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + protected UmbracoApiControllerBase(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) { UmbracoContextAccessor = umbracoContextAccessor; + BackOfficeSecurityAccessor = backOfficeSecurityAccessor; SqlContext = sqlContext; Services = services; AppCaches = appCaches; @@ -82,6 +84,8 @@ namespace Umbraco.Web.WebApi /// public virtual IUmbracoContextAccessor UmbracoContextAccessor { get; } + public IBackOfficeSecurityAccessor BackOfficeSecurityAccessor { get; } + /// /// Gets the sql context. @@ -118,7 +122,7 @@ namespace Umbraco.Web.WebApi /// /// Gets the web security helper. /// - public IBackOfficeSecurity Security => UmbracoContext.Security; + public IBackOfficeSecurity Security => BackOfficeSecurityAccessor.BackOfficeSecurity; /// /// Tries to get the current HttpContext. diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs index 8e414be5ef..dea72b7be9 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.WebApi private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IBackOfficeSecurity BackOfficeSecurity => _backOfficeSecurityAccessor.BackOfficeSecurity ?? Current.UmbracoContext.Security; + private IBackOfficeSecurity BackOfficeSecurity => _backOfficeSecurityAccessor.BackOfficeSecurity ?? Current.BackOfficeSecurityAccessor.BackOfficeSecurity; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 87627501bd..f744213276 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Security; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; using Umbraco.Web.Routing; namespace Umbraco.Web.WebApi @@ -36,8 +37,8 @@ namespace Umbraco.Web.WebApi { } - protected UmbracoAuthorizedApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) + protected UmbracoAuthorizedApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + : base(globalSettings, umbracoContextAccessor, backOfficeSecurityAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } diff --git a/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComposer.cs b/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComposer.cs index bb8c2be059..c591191524 100644 --- a/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComposer.cs +++ b/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComposer.cs @@ -1,4 +1,5 @@ using Umbraco.Core; +using Umbraco.Core.Builder; using Umbraco.Core.Composing; using Umbraco.Core.WebAssets; @@ -6,10 +7,10 @@ namespace Umbraco.Web.WebAssets.CDF { public sealed class ClientDependencyComposer : ComponentComposer { - public override void Compose(Composition composition) + public override void Compose(IUmbracoBuilder builder) { - base.Compose(composition); - composition.Services.AddUnique(); + base.Compose(builder); + builder.Services.AddUnique(); } } } diff --git a/src/umbraco-netcore-only.sln b/src/umbraco-netcore-only.sln new file mode 100644 index 0000000000..f9e749c59d --- /dev/null +++ b/src/umbraco-netcore-only.sln @@ -0,0 +1,205 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.152 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4-3B4E-40A3-A309-F3CB4F0E125F}" + ProjectSection(SolutionItems) = preProject + ..\build\build-bootstrap.ps1 = ..\build\build-bootstrap.ps1 + ..\build\build.ps1 = ..\build\build.ps1 + ..\NuGet.Config = ..\NuGet.Config + SolutionInfo.cs = SolutionInfo.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{FD962632-184C-4005-A5F3-E705D92FC645}" + ProjectSection(SolutionItems) = preProject + ..\.github\BUILD.md = ..\.github\BUILD.md + ..\.github\CLEAR.md = ..\.github\CLEAR.md + ..\.github\CODE_OF_CONDUCT.md = ..\.github\CODE_OF_CONDUCT.md + ..\.github\CONTRIBUTING.md = ..\.github\CONTRIBUTING.md + ..\.github\CONTRIBUTING_DETAILED.md = ..\.github\CONTRIBUTING_DETAILED.md + ..\.github\CONTRIBUTION_GUIDELINES.md = ..\.github\CONTRIBUTION_GUIDELINES.md + ..\.github\PULL_REQUEST_TEMPLATE.md = ..\.github\PULL_REQUEST_TEMPLATE.md + ..\.github\README.md = ..\.github\README.md + ..\.github\REVIEW_PROCESS.md = ..\.github\REVIEW_PROCESS.md + ..\.github\V8_GETTING_STARTED.md = ..\.github\V8_GETTING_STARTED.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B5BD12C1-A454-435E-8A46-FF4A364C0382}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{227C3B55-80E5-4E7E-A802-BE16C5128B9D}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\UmbracoCms.Core.nuspec = ..\build\NuSpecs\UmbracoCms.Core.nuspec + ..\build\NuSpecs\UmbracoCms.nuspec = ..\build\NuSpecs\UmbracoCms.nuspec + ..\build\NuSpecs\UmbracoCms.SqlCe.nuspec = ..\build\NuSpecs\UmbracoCms.SqlCe.nuspec + ..\build\NuSpecs\UmbracoCms.Web.nuspec = ..\build\NuSpecs\UmbracoCms.Web.nuspec + EndProjectSection +EndProject +Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Web.UI.Client", "http://localhost:3961", "{3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}" + ProjectSection(WebsiteProperties) = preProject + UseIISExpress = "true" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5" + Debug.AspNetCompiler.VirtualPath = "/localhost_3961" + Debug.AspNetCompiler.PhysicalPath = "Umbraco.Web.UI.Client\" + Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_3961\" + Debug.AspNetCompiler.Updateable = "true" + Debug.AspNetCompiler.ForceOverwrite = "true" + Debug.AspNetCompiler.FixedNames = "false" + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.VirtualPath = "/localhost_3961" + Release.AspNetCompiler.PhysicalPath = "Umbraco.Web.UI.Client\" + Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_3961\" + Release.AspNetCompiler.Updateable = "true" + Release.AspNetCompiler.ForceOverwrite = "true" + Release.AspNetCompiler.FixedNames = "false" + Release.AspNetCompiler.Debug = "False" + SlnRelativePath = "Umbraco.Web.UI.Client\" + DefaultWebSiteLanguage = "Visual C#" + StartServerOnDebug = "false" + EndProjectSection +EndProject +Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Tests.AcceptanceTest", "http://localhost:58896", "{9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}" + ProjectSection(WebsiteProperties) = preProject + UseIISExpress = "true" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5" + Debug.AspNetCompiler.VirtualPath = "/localhost_62926" + Debug.AspNetCompiler.PhysicalPath = "Umbraco.Tests.AcceptanceTest\" + Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_62926\" + Debug.AspNetCompiler.Updateable = "true" + Debug.AspNetCompiler.ForceOverwrite = "true" + Debug.AspNetCompiler.FixedNames = "false" + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.VirtualPath = "/localhost_62926" + Release.AspNetCompiler.PhysicalPath = "Umbraco.Tests.AcceptanceTest\" + Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_62926\" + Release.AspNetCompiler.Updateable = "true" + Release.AspNetCompiler.ForceOverwrite = "true" + Release.AspNetCompiler.FixedNames = "false" + Release.AspNetCompiler.Debug = "False" + SlnRelativePath = "Umbraco.Tests.AcceptanceTest\" + DefaultWebSiteLanguage = "Visual C#" + StartServerOnDebug = "false" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{E3F9F378-AFE1-40A5-90BD-82833375DBFE}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\tools\applications.config.install.xdt = ..\build\NuSpecs\tools\applications.config.install.xdt + ..\build\NuSpecs\tools\ClientDependency.config.install.xdt = ..\build\NuSpecs\tools\ClientDependency.config.install.xdt + ..\build\NuSpecs\tools\install.ps1 = ..\build\NuSpecs\tools\install.ps1 + ..\build\NuSpecs\tools\Readme.txt = ..\build\NuSpecs\tools\Readme.txt + ..\build\NuSpecs\tools\ReadmeUpgrade.txt = ..\build\NuSpecs\tools\ReadmeUpgrade.txt + ..\build\NuSpecs\tools\serilog.config.install.xdt = ..\build\NuSpecs\tools\serilog.config.install.xdt + ..\build\NuSpecs\tools\Web.config.install.xdt = ..\build\NuSpecs\tools\Web.config.install.xdt + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{5B03EF4E-E0AC-4905-861B-8C3EC1A0D458}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\build\Umbraco.Cms.props = ..\build\NuSpecs\build\Umbraco.Cms.props + ..\build\NuSpecs\build\Umbraco.Cms.targets = ..\build\NuSpecs\build\Umbraco.Cms.targets + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DocTools", "DocTools", "{53594E5B-64A2-4545-8367-E3627D266AE8}" + ProjectSection(SolutionItems) = preProject + ApiDocs\docfx.filter.yml = ApiDocs\docfx.filter.yml + ApiDocs\docfx.json = ApiDocs\docfx.json + ApiDocs\index.md = ApiDocs\index.md + ApiDocs\toc.yml = ApiDocs\toc.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IssueTemplates", "IssueTemplates", "{C7311C00-2184-409B-B506-52A5FAEA8736}" + ProjectSection(SolutionItems) = preProject + ..\.github\ISSUE_TEMPLATE\1_Bug.md = ..\.github\ISSUE_TEMPLATE\1_Bug.md + ..\.github\ISSUE_TEMPLATE\2_Feature_request.md = ..\.github\ISSUE_TEMPLATE\2_Feature_request.md + ..\.github\ISSUE_TEMPLATE\3_Support_question.md = ..\.github\ISSUE_TEMPLATE\3_Support_question.md + ..\.github\ISSUE_TEMPLATE\4_Documentation_issue.md = ..\.github\ISSUE_TEMPLATE\4_Documentation_issue.md + ..\.github\ISSUE_TEMPLATE\5_Security_issue.md = ..\.github\ISSUE_TEMPLATE\5_Security_issue.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Core", "Umbraco.Core\Umbraco.Core.csproj", "{29AA69D9-B597-4395-8D42-43B1263C240A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.ModelsBuilder.Embedded", "Umbraco.ModelsBuilder.Embedded\Umbraco.ModelsBuilder.Embedded.csproj", "{52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Infrastructure", "Umbraco.Infrastructure\Umbraco.Infrastructure.csproj", "{3AE7BF57-966B-45A5-910A-954D7C554441}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.PublishedCache.NuCache", "Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj", "{F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.BackOffice", "Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj", "{9B95EEF7-63FE-4432-8C63-166BE9C1A929}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.UI.NetCore", "Umbraco.Web.UI.NetCore\Umbraco.Web.UI.NetCore.csproj", "{DCDFE97C-5630-4F6F-855D-8AEEB96556A5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Website", "Umbraco.Web.Website\Umbraco.Web.Website.csproj", "{5A246D54-3109-4D2B-BE7D-FC0787D126AE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Tests.Common", "Umbraco.Tests.Common\Umbraco.Tests.Common.csproj", "{A499779C-1B3B-48A8-B551-458E582E6E96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Tests.UnitTests", "Umbraco.Tests.UnitTests\Umbraco.Tests.UnitTests.csproj", "{9102ABDF-E537-4E46-B525-C9ED4833EED0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Common", "Umbraco.Web.Common\Umbraco.Web.Common.csproj", "{79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Release|Any CPU.Build.0 = Release|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Release|Any CPU.Build.0 = Release|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.Build.0 = Release|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Release|Any CPU.Build.0 = Release|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Release|Any CPU.Build.0 = Release|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Release|Any CPU.Build.0 = Release|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.Build.0 = Release|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.Build.0 = Release|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.Build.0 = Release|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {227C3B55-80E5-4E7E-A802-BE16C5128B9D} = {2849E9D4-3B4E-40A3-A309-F3CB4F0E125F} + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + {E3F9F378-AFE1-40A5-90BD-82833375DBFE} = {227C3B55-80E5-4E7E-A802-BE16C5128B9D} + {5B03EF4E-E0AC-4905-861B-8C3EC1A0D458} = {227C3B55-80E5-4E7E-A802-BE16C5128B9D} + {53594E5B-64A2-4545-8367-E3627D266AE8} = {FD962632-184C-4005-A5F3-E705D92FC645} + {C7311C00-2184-409B-B506-52A5FAEA8736} = {FD962632-184C-4005-A5F3-E705D92FC645} + {A499779C-1B3B-48A8-B551-458E582E6E96} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + {9102ABDF-E537-4E46-B525-C9ED4833EED0} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7A0F2E34-D2AF-4DAB-86A0-7D7764B3D0EC} + EndGlobalSection +EndGlobal