From ce47eae85b4348d067ae7cfb5c4c5044a277df31 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 23 Nov 2018 16:19:03 +0100 Subject: [PATCH] Various fixes --- src/Umbraco.Core/Components/BootLoader.cs | 16 ++-- ...ute.cs => RequiredByComponentAttribute.cs} | 6 +- .../Composing/ContainerFactory.cs | 4 - src/Umbraco.Core/Composing/IContainer.cs | 1 - src/Umbraco.Core/Runtime/CoreRuntime.cs | 17 +--- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- .../Components/ComponentTests.cs | 6 +- .../Repositories/StylesheetRepositoryTest.cs | 27 +++---- src/Umbraco.Web/Actions/ActionCollection.cs | 78 +++---------------- .../Actions/ActionCollectionBuilder.cs | 21 +++-- .../Cache/CacheRefresherComponent.cs | 2 +- src/Umbraco.Web/UmbracoApplicationBase.cs | 5 +- src/Umbraco.Web/UmbracoContext.cs | 2 +- 13 files changed, 54 insertions(+), 133 deletions(-) rename src/Umbraco.Core/Components/{RequiredComponentAttribute.cs => RequiredByComponentAttribute.cs} (92%) diff --git a/src/Umbraco.Core/Components/BootLoader.cs b/src/Umbraco.Core/Components/BootLoader.cs index e2ab754956..ff0b7ab05b 100644 --- a/src/Umbraco.Core/Components/BootLoader.cs +++ b/src/Umbraco.Core/Components/BootLoader.cs @@ -135,7 +135,7 @@ namespace Umbraco.Core.Components text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue ? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")")) : "")); - foreach (var attribute in type.GetCustomAttributes()) + foreach (var attribute in type.GetCustomAttributes()) text.AppendLine(" -< " + attribute.RequiringType); foreach (var i in type.GetInterfaces()) { @@ -144,7 +144,7 @@ namespace Umbraco.Core.Components text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue ? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")")) : "")); - foreach (var attribute in i.GetCustomAttributes()) + foreach (var attribute in i.GetCustomAttributes()) text.AppendLine(" -< " + attribute.RequiringType); } if (kvp.Value != null) @@ -221,7 +221,7 @@ namespace Umbraco.Core.Components if (requirements[type] == null) requirements[type] = new List(); requirements[type].AddRange(implems); } - else if (attr.Weak == false) // if explicitely set to !weak, is strong, else is weak + else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak throw new Exception($"Broken component dependency: {type.FullName} -> {attr.RequiredType.FullName}."); } // requiring a class = require that the component is enabled @@ -233,7 +233,7 @@ namespace Umbraco.Core.Components if (requirements[type] == null) requirements[type] = new List(); requirements[type].Add(attr.RequiredType); } - else if (attr.Weak != true) // if not explicitely set to weak, is strong + else if (attr.Weak != true) // if not explicitly set to weak, is strong throw new Exception($"Broken component dependency: {type.FullName} -> {attr.RequiredType.FullName}."); } } @@ -244,8 +244,8 @@ namespace Umbraco.Core.Components // get 'required' attributes // these attributes are *not* inherited because we want to "custom-inherit" for interfaces only var requiredAttributes = type - .GetInterfaces().SelectMany(x => x.GetCustomAttributes()) // those marking interfaces - .Concat(type.GetCustomAttributes()); // those marking the component + .GetInterfaces().SelectMany(x => x.GetCustomAttributes()) // those marking interfaces + .Concat(type.GetCustomAttributes()); // those marking the component foreach (var attr in requiredAttributes) { @@ -275,7 +275,7 @@ namespace Umbraco.Core.Components private void InstantiateComponents(IEnumerable types) { - using (_proflog.DebugDuration("Instanciating components.", "Instanciated components.")) + using (_proflog.DebugDuration("Instantiating components.", "Instantiated components.")) { _components = types.Select(x => (IUmbracoComponent) Activator.CreateInstance(x)).ToArray(); } @@ -309,7 +309,7 @@ namespace Umbraco.Core.Components var componentType = component.GetType(); var initializers = componentType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(x => x.Name == "Initialize" && x.IsGenericMethod == false && x.IsStatic == false); - using (_proflog.DebugDuration($"Initializing {componentType.FullName}.", $"Initialised {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) + using (_proflog.DebugDuration($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { foreach (var initializer in initializers) { diff --git a/src/Umbraco.Core/Components/RequiredComponentAttribute.cs b/src/Umbraco.Core/Components/RequiredByComponentAttribute.cs similarity index 92% rename from src/Umbraco.Core/Components/RequiredComponentAttribute.cs rename to src/Umbraco.Core/Components/RequiredByComponentAttribute.cs index 0a542b9fd6..9d206b564b 100644 --- a/src/Umbraco.Core/Components/RequiredComponentAttribute.cs +++ b/src/Umbraco.Core/Components/RequiredByComponentAttribute.cs @@ -19,13 +19,13 @@ namespace Umbraco.Core.Components /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] - public class RequiredComponentAttribute : Attribute + public class RequiredByComponentAttribute : Attribute { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The type of the required component. - public RequiredComponentAttribute(Type requiringType) + public RequiredByComponentAttribute(Type requiringType) { if (typeof(IUmbracoComponent).IsAssignableFrom(requiringType) == false) throw new ArgumentException($"Type {requiringType.FullName} is invalid here because it does not implement {typeof(IUmbracoComponent).FullName}."); diff --git a/src/Umbraco.Core/Composing/ContainerFactory.cs b/src/Umbraco.Core/Composing/ContainerFactory.cs index bf808d56ae..fb2c5f6eb7 100644 --- a/src/Umbraco.Core/Composing/ContainerFactory.cs +++ b/src/Umbraco.Core/Composing/ContainerFactory.cs @@ -50,10 +50,6 @@ namespace Umbraco.Core.Composing if (container == null) throw new Exception($"Container factory '{configuredTypeName}' did not return an IContainer implementation."); - // self-register the container - this is where it should happen - // but - we do NOT want to do it! - //container.RegisterInstance(container); - return container; } } diff --git a/src/Umbraco.Core/Composing/IContainer.cs b/src/Umbraco.Core/Composing/IContainer.cs index 0d4fcb0d98..d068339eb1 100644 --- a/src/Umbraco.Core/Composing/IContainer.cs +++ b/src/Umbraco.Core/Composing/IContainer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Composing.LightInject; namespace Umbraco.Core.Composing { diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 5d64f75adb..3004c7566a 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -14,7 +14,6 @@ using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; @@ -32,16 +31,11 @@ namespace Umbraco.Core.Runtime private BootLoader _bootLoader; private RuntimeState _state; - /// - /// Initializes a new instance of the class. - /// - public CoreRuntime() - { } - /// public virtual void Boot(IContainer container) { - container.ConfigureUmbracoCore(); // also sets Current.Container + // assign current container + Current.Container = container; // register the essential stuff, // ie the global application logger @@ -109,13 +103,6 @@ namespace Umbraco.Core.Runtime // throw a BootFailedException for every requests. } } - - //fixme - // after Umbraco has started there is a scope in "context" and that context is - // going to stay there and never get destroyed nor reused, so we have to ensure that - // everything is cleared - //var sa = container.GetInstance(); - //sa.Scope?.Dispose(); } /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 077487c8be..1b517ae1f9 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -165,7 +165,7 @@ - + diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs index a78f9f3249..a537aac4ae 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests/Components/ComponentTests.cs @@ -296,7 +296,7 @@ namespace Umbraco.Tests.Components public class Component12 : TestComponentBase, IUmbracoCoreComponent { } - [RequiredComponent(typeof(Component1))] + [RequiredByComponent(typeof(Component1))] public class Component13 : TestComponentBase { } @@ -307,7 +307,7 @@ namespace Umbraco.Tests.Components public class Component20 : TestComponentBase { } - [RequiredComponent(typeof(Component20))] + [RequiredByComponent(typeof(Component20))] public class Component21 : TestComponentBase { } @@ -322,7 +322,7 @@ namespace Umbraco.Tests.Components { } // should insert itself between 22 and anything i23 - [RequiredComponent(typeof(IComponent23))] + [RequiredByComponent(typeof(IComponent23))] //[RequireComponent(typeof(Component22))] - not needed, implement i23 public class Component25 : TestComponentBase, IComponent23 { } diff --git a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs index a1acbca1e9..6fae1d4749 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Text; +using Moq; using NUnit.Framework; using Umbraco.Core.IO; using Umbraco.Core.Models; @@ -55,7 +56,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var stylesheet = new Stylesheet("test-add.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + //Assert Assert.That(_fileSystem.FileExists("test-add.css"), Is.True); @@ -73,12 +74,12 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var stylesheet = new Stylesheet("test-update.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + var stylesheetUpdate = repository.Get("test-update.css"); stylesheetUpdate.Content = "body { color:#000; }"; repository.Save(stylesheetUpdate); - + var stylesheetUpdated = repository.Get("test-update.css"); @@ -100,12 +101,12 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var stylesheet = new Stylesheet("test-update.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + stylesheet.AddProperty(new StylesheetProperty("Test", "p", "font-size:2em;")); repository.Save(stylesheet); - + //re-get stylesheet = repository.Get(stylesheet.Name); @@ -127,7 +128,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var stylesheet = new Stylesheet("test-update.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + stylesheet.AddProperty(new StylesheetProperty("Test", "p", "font-size:2em;")); @@ -146,10 +147,10 @@ namespace Umbraco.Tests.Persistence.Repositories // Act var stylesheet = new Stylesheet("test-delete.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + repository.Delete(stylesheet); - + //Assert Assert.That(_fileSystem.FileExists("test-delete.css"), Is.False); @@ -185,7 +186,7 @@ namespace Umbraco.Tests.Persistence.Repositories var stylesheet = new Stylesheet("styles-v2.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + // Act var stylesheets = repository.GetMany(); @@ -208,7 +209,7 @@ namespace Umbraco.Tests.Persistence.Repositories var stylesheet = new Stylesheet("styles-v2.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + // Act var stylesheets = repository.GetMany("styles-v2.css", "styles.css"); @@ -248,14 +249,14 @@ namespace Umbraco.Tests.Persistence.Repositories var stylesheet = new Stylesheet("test-path-1.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + Assert.IsTrue(_fileSystem.FileExists("test-path-1.css")); Assert.AreEqual("test-path-1.css", stylesheet.Path); Assert.AreEqual("/css/test-path-1.css", stylesheet.VirtualPath); stylesheet = new Stylesheet("path-2/test-path-2.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-2.css")); Assert.AreEqual("path-2\\test-path-2.css", stylesheet.Path); // fixed in 7.3 - 7.2.8 does not update the path Assert.AreEqual("/css/path-2/test-path-2.css", stylesheet.VirtualPath); @@ -267,7 +268,7 @@ namespace Umbraco.Tests.Persistence.Repositories stylesheet = new Stylesheet("path-2\\test-path-3.css") { Content = "body { color:#000; } .bold {font-weight:bold;}" }; repository.Save(stylesheet); - + Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-3.css")); Assert.AreEqual("path-2\\test-path-3.css", stylesheet.Path); Assert.AreEqual("/css/path-2/test-path-3.css", stylesheet.VirtualPath); diff --git a/src/Umbraco.Web/Actions/ActionCollection.cs b/src/Umbraco.Web/Actions/ActionCollection.cs index 23b33d5f67..0e33f03103 100644 --- a/src/Umbraco.Web/Actions/ActionCollection.cs +++ b/src/Umbraco.Web/Actions/ActionCollection.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; +using System.Collections.Generic; using System.Linq; -using System.Reflection; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.Membership; @@ -11,16 +7,11 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Actions { - public class ActionCollection : IBuilderCollection + public class ActionCollection : BuilderCollectionBase { - private Func> _producer; - private readonly object _locker = new object(); - private IAction[] _items; - - internal ActionCollection(Func> producer) - { - _producer = producer; - } + public ActionCollection(IEnumerable items) + : base(items) + { } internal T GetAction() where T : IAction @@ -30,66 +21,19 @@ namespace Umbraco.Web.Actions internal IEnumerable GetByLetters(IEnumerable letters) { - var all = this.ToArray(); - return letters.Select(x => all.FirstOrDefault(y => y.Letter.ToString(CultureInfo.InvariantCulture) == x)) + return letters + .Where(x => x.Length == 1) + .Select(x => this.FirstOrDefault(y => y.Letter == x[0])) .WhereNotNull() - .ToArray(); + .ToList(); } - private IAction[] Items - { - get - { - lock (_locker) - { - if (_items != null) return _items; - // fixme - // why is this not a builder collection base anymore? - // - var actions = new List(); - foreach (var type in _producer()) - { - var getter = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static); - var instance = getter == null - ? Activator.CreateInstance(type) as IAction - : getter.GetValue(null, null) as IAction; - if (instance == null) continue; - actions.Add(instance); - } - - return _items = actions.ToArray(); - } - } - } - - internal void Reset(Func> producer) - { - lock (_locker) - { - _items = null; - _producer = producer; - } - } - - public int Count => Items.Length; - - public IEnumerator GetEnumerator() - { - return ((IEnumerable) Items).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - internal IReadOnlyList FromEntityPermission(EntityPermission entityPermission) { return entityPermission.AssignedPermissions .Where(x => x.Length == 1) - .Select(x => x.ToCharArray()[0]) - .SelectMany(c => this.Where(x => x.Letter == c)) - .Where(action => action != null) + .SelectMany(x => this.Where(y => y.Letter == x[0])) + .WhereNotNull() .ToList(); } } diff --git a/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs b/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs index 6002c8d2b0..027a3fcd9b 100644 --- a/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs +++ b/src/Umbraco.Web/Actions/ActionCollectionBuilder.cs @@ -1,31 +1,28 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using LightInject; using Umbraco.Core.Composing; - namespace Umbraco.Web.Actions { internal class ActionCollectionBuilder : LazyCollectionBuilderBase { - public ActionCollectionBuilder(IServiceContainer container) + public ActionCollectionBuilder(IContainer container) : base(container) { } protected override ActionCollectionBuilder This => this; - protected override IEnumerable CreateItems(params object[] args) + protected override IEnumerable CreateItems() { - var items = base.CreateItems(args).ToList(); + var items = base.CreateItems().ToList(); + //validate the items, no actions should exist that do not either expose notifications or permissions - var invalid = items.Where(x => !x.CanBePermissionAssigned && !x.ShowInNotifier).ToList(); - if (invalid.Count > 0) - { - throw new InvalidOperationException($"Invalid actions '{string.Join(", ", invalid.Select(x => x.Alias))}'. All {typeof(IAction)} implementations must be true for either {nameof(IAction.CanBePermissionAssigned)} or {nameof(IAction.ShowInNotifier)}"); - } - return items; + var invalidItems = items.Where(x => !x.CanBePermissionAssigned && !x.ShowInNotifier).ToList(); + if (invalidItems.Count == 0) return items; + + var invalidActions = string.Join(", ", invalidItems.Select(x => "'" + x.Alias + "'")); + throw new InvalidOperationException($"Invalid actions {invalidActions}'. All {typeof(IAction)} implementations must be true for either {nameof(IAction.CanBePermissionAssigned)} or {nameof(IAction.ShowInNotifier)}."); } } } diff --git a/src/Umbraco.Web/Cache/CacheRefresherComponent.cs b/src/Umbraco.Web/Cache/CacheRefresherComponent.cs index 7f6de38418..3a5f716552 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherComponent.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherComponent.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.Cache /// Installs listeners on service events in order to refresh our caches. /// [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - [RequiredComponent(typeof(IUmbracoCoreComponent))] // runs before every other IUmbracoCoreComponent! + [RequiredByComponent(typeof(IUmbracoCoreComponent))] // runs before every other IUmbracoCoreComponent! public class CacheRefresherComponent : UmbracoComponentBase, IUmbracoCoreComponent { private static readonly ConcurrentDictionary FoundHandlers = new ConcurrentDictionary(); diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index b680f340c5..b778a04967 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -58,12 +58,9 @@ namespace Umbraco.Web { // ******** THIS IS WHERE EVERYTHING BEGINS ******** - // create the container for the application, and configure. + // create the container for the application, and boot // the boot manager is responsible for registrations var container = GetContainer(); - Current.Container = container; // fixme NOT HERE OR WHAT? - - // get runtime & boot _runtime = GetRuntime(); _runtime.Boot(container); } diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 19a79a7492..8ee5910bae 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -5,13 +5,13 @@ using System.Web; using System.Web.Hosting; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Runtime; using Umbraco.Web.Security; -using LightInject; namespace Umbraco.Web {