Refactor runtimes, injection and composition

This commit is contained in:
Stephan
2018-11-26 16:54:32 +01:00
parent 8b74453c13
commit b8608f1b2e
73 changed files with 711 additions and 829 deletions
@@ -4,10 +4,6 @@ namespace Umbraco.Core.Cache
{
public class CacheRefresherCollectionBuilder : LazyCollectionBuilderBase<CacheRefresherCollectionBuilder, CacheRefresherCollection, ICacheRefresher>
{
public CacheRefresherCollectionBuilder(IContainer container)
: base(container)
{ }
protected override CacheRefresherCollectionBuilder This => this;
}
}
@@ -13,25 +13,26 @@ namespace Umbraco.Core.Components
{
// note: this class is NOT thread-safe in any ways
internal class BootLoader
internal class Components
{
private readonly IContainer _container;
private readonly ProfilingLogger _proflog;
private readonly ILogger _logger;
private readonly Composition _composition;
private readonly IProfilingLogger _logger;
private readonly IEnumerable<Type> _componentTypes;
private IUmbracoComponent[] _components;
private bool _booted;
private const int LogThresholdMilliseconds = 100;
/// <summary>
/// Initializes a new instance of the <see cref="BootLoader"/> class.
/// Initializes a new instance of the <see cref="Components"/> class.
/// </summary>
/// <param name="container">The application container.</param>
public BootLoader(IContainer container)
/// <param name="composition">The composition.</param>
/// <param name="componentTypes">The component types.</param>
/// <param name="logger">A profiling logger.</param>
public Components(Composition composition, IEnumerable<Type> componentTypes, IProfilingLogger logger)
{
_container = container ?? throw new ArgumentNullException(nameof(container));
_proflog = container.GetInstance<ProfilingLogger>();
_logger = container.GetInstance<ILogger>();
_composition = composition ?? throw new ArgumentNullException(nameof(composition));
_componentTypes = componentTypes ?? throw new ArgumentNullException(nameof(componentTypes));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
private class EnableInfo
@@ -40,44 +41,42 @@ namespace Umbraco.Core.Components
public int Weight = -1;
}
public void Boot(IEnumerable<Type> componentTypes, RuntimeLevel level)
public void Compose()
{
if (_booted) throw new InvalidOperationException("Can not boot, has already booted.");
var orderedComponentTypes = PrepareComponentTypes(componentTypes, level);
var orderedComponentTypes = PrepareComponentTypes();
InstantiateComponents(orderedComponentTypes);
ComposeComponents(level);
ComposeComponents();
}
using (var scope = _container.GetInstance<IScopeProvider>().CreateScope())
public void Initialize()
{
using (var scope = _composition.Container.GetInstance<IScopeProvider>().CreateScope())
{
InitializeComponents();
scope.Complete();
}
// rejoice!
_booted = true;
}
private IEnumerable<Type> PrepareComponentTypes(IEnumerable<Type> componentTypes, RuntimeLevel level)
private IEnumerable<Type> PrepareComponentTypes()
{
using (_proflog.DebugDuration<BootLoader>("Preparing component types.", "Prepared component types."))
using (_logger.DebugDuration<Components>("Preparing component types.", "Prepared component types."))
{
return PrepareComponentTypes2(componentTypes, level);
return PrepareComponentTypes2();
}
}
private IEnumerable<Type> PrepareComponentTypes2(IEnumerable<Type> componentTypes, RuntimeLevel level)
private IEnumerable<Type> PrepareComponentTypes2()
{
// create a list, remove those that cannot be enabled due to runtime level
var componentTypeList = componentTypes
var componentTypeList = _componentTypes
.Where(x =>
{
// use the min level specified by the attribute if any
// otherwise, user components have Run min level, anything else is Unknown (always run)
var attr = x.GetCustomAttribute<RuntimeLevelAttribute>();
var minLevel = attr?.MinLevel ?? (x.Implements<IUmbracoUserComponent>() ? RuntimeLevel.Run : RuntimeLevel.Unknown);
return level >= minLevel;
return _composition.RuntimeLevel >= minLevel;
})
.ToList();
@@ -107,15 +106,15 @@ namespace Umbraco.Core.Components
catch (Exception e)
{
// in case of an error, force-dump everything to log
_logger.Info<BootLoader>("Component Report:\r\n{ComponentReport}", GetComponentsReport(requirements));
_logger.Error<BootLoader>(e, "Failed to sort components.");
_logger.Info<Components>("Component Report:\r\n{ComponentReport}", GetComponentsReport(requirements));
_logger.Error<Components>(e, "Failed to sort components.");
throw;
}
// bit verbose but should help for troubleshooting
var text = "Ordered Components: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComponentTypes) + Environment.NewLine;
Console.WriteLine(text);
_logger.Debug<BootLoader>("Ordered Components: {SortedComponentTypes}", sortedComponentTypes);
_logger.Debug<Components>("Ordered Components: {SortedComponentTypes}", sortedComponentTypes);
return sortedComponentTypes;
}
@@ -275,23 +274,23 @@ namespace Umbraco.Core.Components
private void InstantiateComponents(IEnumerable<Type> types)
{
using (_proflog.DebugDuration<BootLoader>("Instantiating components.", "Instantiated components."))
using (_logger.DebugDuration<Components>("Instantiating components.", "Instantiated components."))
{
// fixme is there a faster way?
_components = types.Select(x => (IUmbracoComponent) Activator.CreateInstance(x)).ToArray();
}
}
private void ComposeComponents(RuntimeLevel level)
private void ComposeComponents()
{
using (_proflog.DebugDuration<BootLoader>($"Composing components. (log when >{LogThresholdMilliseconds}ms)", "Composed components."))
using (_logger.DebugDuration<Components>($"Composing components. (log when >{LogThresholdMilliseconds}ms)", "Composed components."))
{
var composition = new Composition(_container, level);
foreach (var component in _components)
{
var componentType = component.GetType();
using (_proflog.DebugDuration<BootLoader>($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
using (_logger.DebugDuration<Components>($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
component.Compose(composition);
component.Compose(_composition);
}
}
}
@@ -301,15 +300,15 @@ namespace Umbraco.Core.Components
{
// use a container scope to ensure that PerScope instances are disposed
// components that require instances that should not survive should register them with PerScope lifetime
using (_proflog.DebugDuration<BootLoader>($"Initializing components. (log when >{LogThresholdMilliseconds}ms)", "Initialized components."))
using (_container.BeginScope())
using (_logger.DebugDuration<Components>($"Initializing components. (log when >{LogThresholdMilliseconds}ms)", "Initialized components."))
using (_composition.Container.BeginScope())
{
foreach (var component in _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<BootLoader>($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
using (_logger.DebugDuration<Components>($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
foreach (var initializer in initializers)
{
@@ -329,7 +328,7 @@ namespace Umbraco.Core.Components
try
{
param = _container.TryGetInstance(parameterType);
param = _composition.Container.TryGetInstance(parameterType);
}
catch (Exception e)
{
@@ -342,19 +341,13 @@ namespace Umbraco.Core.Components
public void Terminate()
{
if (_booted == false)
{
_proflog.Logger.Warn<BootLoader>("Cannot terminate, has not booted.");
return;
}
using (_proflog.DebugDuration<BootLoader>($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated."))
using (_logger.DebugDuration<Components>($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated."))
{
for (var i = _components.Length - 1; i >= 0; i--) // terminate components in reverse order
{
var component = _components[i];
var componentType = component.GetType();
using (_proflog.DebugDuration<BootLoader>($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
using (_logger.DebugDuration<Components>($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
component.Terminate();
}
+26 -1
View File
@@ -1,4 +1,6 @@
using Umbraco.Core.Composing;
using System;
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Components
{
@@ -12,6 +14,8 @@ namespace Umbraco.Core.Components
/// may cause issues.</remarks>
public class Composition
{
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
/// <summary>
/// Initializes a new instance of the <see cref="Composition"/> class.
/// </summary>
@@ -33,5 +37,26 @@ namespace Umbraco.Core.Components
/// Gets the runtime level.
/// </summary>
public RuntimeLevel RuntimeLevel { get; }
/// <summary>
/// Gets a collection builder (and registers the collection).
/// </summary>
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
/// <returns>The collection builder.</returns>
public TBuilder GetCollectionBuilder<TBuilder>()
where TBuilder: ICollectionBuilder, new()
{
var typeOfBuilder = typeof(TBuilder);
if (_builders.TryGetValue(typeOfBuilder, out var o))
return (TBuilder) o;
var builder = new TBuilder();
builder.Initialize(Container);
_builders[typeOfBuilder] = builder;
return builder;
}
}
}
@@ -16,25 +16,12 @@ namespace Umbraco.Core.Composing
{
private readonly List<Type> _types = new List<Type>();
private readonly object _locker = new object();
private Func<IEnumerable<TItem>, TCollection> _collectionCtor;
private Type[] _registeredTypes;
/// <summary>
/// Initializes a new instance of the <see cref="CollectionBuilderBase{TBuilder, TCollection,TItem}"/>
/// class with a service container.
/// </summary>
/// <param name="container">A container.</param>
protected CollectionBuilderBase(IContainer container)
{
Container = container;
// ReSharper disable once DoNotCallOverridableMethodsInConstructor
Initialize();
}
/// <summary>
/// Gets the container.
/// </summary>
protected IContainer Container { get; }
protected IContainer Container { get; private set; }
/// <summary>
/// Gets the internal list of types as an IEnumerable (immutable).
@@ -44,17 +31,13 @@ namespace Umbraco.Core.Composing
/// <summary>
/// Initializes a new instance of the builder.
/// </summary>
/// <remarks>This is called by the constructor and, by default, registers the
/// collection automatically.</remarks>
protected virtual void Initialize()
/// <remarks>By default, this registers the collection automatically.</remarks>
public virtual void Initialize(IContainer container)
{
// compile the auto-collection constructor
// can be null, if no ctor found, and then assume CreateCollection has been overriden
_collectionCtor = ReflectionUtilities.EmitConstructor<Func<IEnumerable<TItem>, TCollection>>(mustExist: false);
if (Container != null)
throw new InvalidOperationException("This builder has already been initialized.");
// we just don't want to support re-registering collections here
if (Container.GetRegistered<TCollection>().Any())
throw new InvalidOperationException("Collection builders cannot be registered once the collection itself has been registered.");
Container = container;
// register the collection
Container.Register(_ => CreateCollection(), CollectionLifetime);
@@ -131,8 +114,7 @@ namespace Umbraco.Core.Composing
/// <remarks>Creates a new collection each time it is invoked.</remarks>
public virtual TCollection CreateCollection()
{
if (_collectionCtor == null) throw new InvalidOperationException("Collection auto-creation is not possible.");
return _collectionCtor(CreateItems());
return Container.CreateInstance<TCollection>(CreateItems());
}
protected Type EnsureType(Type type, string action)
@@ -97,26 +97,6 @@ namespace Umbraco.Core.Composing
public static void RegisterAuto<TServiceBase>(this IContainer container)
=> container.RegisterAuto(typeof(TServiceBase));
/// <summary>
/// Registers and instantiates a collection builder.
/// </summary>
/// <typeparam name="TBuilder">The type of the collection builder.</typeparam>
/// <returns>A collection builder of the specified type.</returns>
public static TBuilder RegisterCollectionBuilder<TBuilder>(this IContainer container)
{
// make sure it's not already registered
// we just don't want to support re-registering collection builders
if (container.GetRegistered<TBuilder>().Any())
throw new InvalidOperationException("Collection builders should be registered only once.");
// register the builder
// use a factory so we don't have to self-register the container
container.RegisterSingleton(factory => factory.CreateInstance<TBuilder>(container));
// initialize and return the builder
return container.GetInstance<TBuilder>();
}
/// <summary>
/// Creates an instance of a service, with arguments.
/// </summary>
@@ -1,11 +1,22 @@
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a collection builder.
/// </summary>
public interface ICollectionBuilder
{
/// <summary>
/// Initializes a new instance of the builder, and registers the collection.
/// </summary>
void Initialize(IContainer container);
}
/// <summary>
/// Represents a collection builder.
/// </summary>
/// <typeparam name="TCollection">The type of the collection.</typeparam>
/// <typeparam name="TItem">The type of the items.</typeparam>
public interface ICollectionBuilder<out TCollection, TItem>
public interface ICollectionBuilder<out TCollection, TItem> : ICollectionBuilder
where TCollection : IBuilderCollection<TItem>
{
/// <summary>
@@ -18,19 +18,12 @@ namespace Umbraco.Core.Composing
private readonly List<Func<IContainer, IEnumerable<Type>>> _producers2 = new List<Func<IContainer, IEnumerable<Type>>>();
private readonly List<Type> _excluded = new List<Type>();
/// <summary>
/// Initializes a new instance of the <see cref="LazyCollectionBuilderBase{TBuilder,TCollection,TItem}"/> class.
/// </summary>
protected LazyCollectionBuilderBase(IContainer container)
: base(container)
{ }
protected abstract TBuilder This { get; }
/// <summary>
/// Clears all types in the collection.
/// </summary>
/// <returns>The buidler.</returns>
/// <returns>The builder.</returns>
public TBuilder Clear()
{
Configure(types =>
@@ -13,20 +13,12 @@ namespace Umbraco.Core.Composing
where TBuilder : OrderedCollectionBuilderBase<TBuilder, TCollection, TItem>
where TCollection : IBuilderCollection<TItem>
{
/// <summary>
/// Initializes a new instance of the <see cref="OrderedCollectionBuilderBase{TBuilder,TCollection,TItem}"/> class.
/// </summary>
/// <param name="container"></param>
protected OrderedCollectionBuilderBase(IContainer container)
: base (container)
{ }
protected abstract TBuilder This { get; }
/// <summary>
/// Clears all types in the collection.
/// </summary>
/// <returns>The buidler.</returns>
/// <returns>The builder.</returns>
public TBuilder Clear()
{
Configure(types => types.Clear());
+13 -13
View File
@@ -16,7 +16,7 @@ using File = System.IO.File;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides methods to find and instanciate types.
/// Provides methods to find and instantiate types.
/// </summary>
/// <remarks>
/// <para>This class should be used to get all types, the <see cref="TypeFinder"/> class should never be used directly.</para>
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Composing
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly IGlobalSettings _globalSettings;
private readonly ProfilingLogger _logger;
private readonly IProfilingLogger _logger;
private readonly object _typesLock = new object();
private readonly Dictionary<TypeListKey, TypeList> _types = new Dictionary<TypeListKey, TypeList>();
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Composing
/// <param name="globalSettings"></param>
/// <param name="logger">A profiling logger.</param>
/// <param name="detectChanges">Whether to detect changes using hashes.</param>
internal TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, ProfilingLogger logger, bool detectChanges = true)
internal TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, IProfilingLogger logger, bool detectChanges = true)
{
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
@@ -192,7 +192,7 @@ namespace Umbraco.Core.Composing
/// <returns>The hash.</returns>
/// <remarks>Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the
/// file properties (false) or the file contents (true).</remarks>
private static string GetFileHash(IEnumerable<Tuple<FileSystemInfo, bool>> filesAndFolders, ProfilingLogger logger)
private static string GetFileHash(IEnumerable<Tuple<FileSystemInfo, bool>> filesAndFolders, IProfilingLogger logger)
{
using (logger.TraceDuration<TypeLoader>("Determining hash of code files on disk", "Hash determined"))
{
@@ -494,7 +494,7 @@ namespace Umbraco.Core.Composing
if (--attempts == 0)
throw;
_logger.Logger.Debug<TypeLoader>("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds);
_logger.Debug<TypeLoader>("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds);
Thread.Sleep(pauseMilliseconds);
}
}
@@ -645,7 +645,7 @@ namespace Umbraco.Core.Composing
if (typeList != null)
{
// need to put some logging here to try to figure out why this is happening: http://issues.umbraco.org/issue/U4-3505
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType));
_logger.Debug<TypeLoader>("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType));
return typeList.Types;
}
@@ -661,7 +661,7 @@ namespace Umbraco.Core.Composing
// report (only once) and scan and update the cache file
if (_reportedChange == false)
{
_logger.Logger.Debug<TypeLoader>("Assemblies changes detected, need to rescan everything.");
_logger.Debug<TypeLoader>("Assemblies changes detected, need to rescan everything.");
_reportedChange = true;
}
}
@@ -676,7 +676,7 @@ namespace Umbraco.Core.Composing
// so in this instance there will never be a result.
if (cacheResult.Exception is CachedTypeNotFoundInFileException || cacheResult.Success == false)
{
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType));
_logger.Debug<TypeLoader>("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType));
scan = true;
}
else
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Composing
catch (Exception ex)
{
// in case of any exception, we have to exit, and revert to scanning
_logger.Logger.Error<TypeLoader>(ex, "Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
_logger.Error<TypeLoader>(ex, "Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
scan = true;
break;
}
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Composing
if (scan == false)
{
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType));
_logger.Debug<TypeLoader>("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType));
}
}
}
@@ -711,7 +711,7 @@ namespace Umbraco.Core.Composing
if (scan)
{
// either we had to scan, or we could not get the types from the cache file - scan now
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: scanning assemblies.", GetName(baseType, attributeType));
_logger.Debug<TypeLoader>("Getting {TypeName}: scanning assemblies.", GetName(baseType, attributeType));
foreach (var t in finder())
typeList.Add(t);
@@ -729,11 +729,11 @@ namespace Umbraco.Core.Composing
UpdateCache();
}
_logger.Logger.Debug<TypeLoader>("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant());
_logger.Debug<TypeLoader>("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant());
}
else
{
_logger.Logger.Debug<TypeLoader>("Got {TypeName}.", GetName(baseType, attributeType));
_logger.Debug<TypeLoader>("Got {TypeName}.", GetName(baseType, attributeType));
}
return typeList.Types;
@@ -42,13 +42,5 @@ namespace Umbraco.Core.Composing
{
return mgr.GetTypesWithAttribute<BaseMapper, MapperForAttribute>();
}
/// <summary>
/// Gets all classes implementing ISqlSyntaxProvider and marked with the SqlSyntaxProviderAttribute.
/// </summary>
public static IEnumerable<Type> GetSqlSyntaxProviders(this TypeLoader mgr)
{
return mgr.GetTypesWithAttribute<ISqlSyntaxProvider, SqlSyntaxProviderAttribute>();
}
}
}
@@ -14,20 +14,12 @@ namespace Umbraco.Core.Composing
where TBuilder : WeightedCollectionBuilderBase<TBuilder, TCollection, TItem>
where TCollection : IBuilderCollection<TItem>
{
/// <summary>
/// Initializes a new instance of the <see cref="WeightedCollectionBuilderBase{TBuilder,TCollection,TItem}"/> class.
/// </summary>
/// <param name="container"></param>
protected WeightedCollectionBuilderBase(IContainer container)
: base(container)
{ }
protected abstract TBuilder This { get; }
/// <summary>
/// Clears all types in the collection.
/// </summary>
/// <returns>The buidler.</returns>
/// <returns>The builder.</returns>
public TBuilder Clear()
{
Configure(types => types.Clear());
@@ -0,0 +1,40 @@
using System;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Defines the profiling logging service.
/// </summary>
public interface IProfilingLogger : ILogger
{
/// <summary>
/// Profiles an action and log as information messages.
/// </summary>
DisposableTimer TraceDuration<T>(string startMessage);
/// <summary>
/// Profiles an action and log as information messages.
/// </summary>
DisposableTimer TraceDuration<T>(string startMessage, string completeMessage, string failMessage = null);
/// <summary>
/// Profiles an action and log as information messages.
/// </summary>
DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null);
/// <summary>
/// Profiles an action and log as debug messages.
/// </summary>
DisposableTimer DebugDuration<T>(string startMessage);
/// <summary>
/// Profiles an action and log as debug messages.
/// </summary>
DisposableTimer DebugDuration<T>(string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0);
/// <summary>
/// Profiles an action and log as debug messages.
/// </summary>
DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0);
}
}
+78 -2
View File
@@ -3,14 +3,23 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Provides debug or trace logging with duration management.
/// Provides logging and profiling services.
/// </summary>
public sealed class ProfilingLogger
public sealed class ProfilingLogger : IProfilingLogger
{
/// <summary>
/// Gets the underlying <see cref="ILogger"/> implementation.
/// </summary>
public ILogger Logger { get; }
/// <summary>
/// Gets the underlying <see cref="IProfiler"/> implementation.
/// </summary>
public IProfiler Profiler { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ProfilingLogger"/> class.
/// </summary>
public ProfilingLogger(ILogger logger, IProfiler profiler)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -52,5 +61,72 @@ namespace Umbraco.Core.Logging
? new DisposableTimer(Logger, LogLevel.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds)
: null;
}
#region ILogger
public bool IsEnabled(Type reporting, LogLevel level)
=> Logger.IsEnabled(reporting, level);
public void Fatal(Type reporting, Exception exception, string message)
=> Logger.Fatal(reporting, exception, message);
public void Fatal(Type reporting, Exception exception)
=> Logger.Fatal(reporting, exception);
public void Fatal(Type reporting, string message)
=> Logger.Fatal(reporting, message);
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
=> Logger.Fatal(reporting, exception, messageTemplate, propertyValues);
public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Fatal(reporting, messageTemplate, propertyValues);
public void Error(Type reporting, Exception exception, string message)
=> Logger.Error(reporting, exception, message);
public void Error(Type reporting, Exception exception)
=> Logger.Error(reporting, exception);
public void Error(Type reporting, string message)
=> Logger.Error(reporting, message);
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
=> Logger.Error(reporting, exception, messageTemplate, propertyValues);
public void Error(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Error(reporting, messageTemplate, propertyValues);
public void Warn(Type reporting, string message)
=> Logger.Warn(reporting, message);
public void Warn(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Warn(reporting, messageTemplate, propertyValues);
public void Warn(Type reporting, Exception exception, string message)
=> Logger.Warn(reporting, exception, message);
public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
=> Logger.Warn(reporting, exception, messageTemplate, propertyValues);
public void Info(Type reporting, string message)
=> Logger.Info(reporting, message);
public void Info(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Info(reporting, messageTemplate, propertyValues);
public void Debug(Type reporting, string message)
=> Logger.Debug(reporting, message);
public void Debug(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Debug(reporting, messageTemplate, propertyValues);
public void Verbose(Type reporting, string message)
=> Logger.Verbose(reporting, message);
public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues)
=> Logger.Verbose(reporting, messageTemplate, propertyValues);
#endregion
}
}
@@ -369,52 +369,6 @@ namespace Umbraco.Core.Migrations.Install
#endregion
#region Utils
internal static void GiveLegacyAChance(IUmbracoDatabaseFactory factory, ILogger logger)
{
// look for the legacy appSettings key
var legacyConnString = ConfigurationManager.AppSettings[Constants.System.UmbracoConnectionName];
if (string.IsNullOrWhiteSpace(legacyConnString)) return;
var test = legacyConnString.ToLowerInvariant();
if (test.Contains("sqlce4umbraco"))
{
// sql ce
ConfigureEmbeddedDatabaseConnection(factory, logger);
}
else if (test.Contains("tcp:"))
{
// sql azure
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
}
else if (test.Contains("datalayer=mysql"))
{
// mysql
// strip the datalayer part off
var connectionStringWithoutDatalayer = string.Empty;
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
connectionStringWithoutDatalayer = $"{connectionStringWithoutDatalayer}{variable};";
SaveConnectionString(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql, logger);
factory.Configure(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql);
}
else
{
// sql server
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
}
// remove the legacy connection string, so we don't end up in a loop if something goes wrong
GlobalSettings.RemoveSetting(Constants.System.UmbracoConnectionName);
}
#endregion
#region Database Schema
internal DatabaseSchemaResult ValidateDatabaseSchema()
@@ -4,10 +4,6 @@ namespace Umbraco.Core.Migrations
{
public class PostMigrationCollectionBuilder : LazyCollectionBuilderBase<PostMigrationCollectionBuilder, PostMigrationCollection, IPostMigration>
{
public PostMigrationCollectionBuilder(IContainer container)
: base(container)
{ }
protected override PostMigrationCollectionBuilder This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient;
@@ -4,15 +4,11 @@ namespace Umbraco.Core.Persistence.Mappers
{
public class MapperCollectionBuilder : LazyCollectionBuilderBase<MapperCollectionBuilder, MapperCollection, BaseMapper>
{
public MapperCollectionBuilder(IContainer container)
: base(container)
{ }
protected override MapperCollectionBuilder This => this;
protected override void Initialize()
public override void Initialize(IContainer container)
{
base.Initialize();
base.Initialize(container);
// default initializer registers
// - service MapperCollectionBuilder, returns MapperCollectionBuilder
@@ -23,7 +19,7 @@ namespace Umbraco.Core.Persistence.Mappers
Container.Register<IMapperCollection>(factory => factory.GetInstance<MapperCollection>());
}
public MapperCollectionBuilder AddCore()
public MapperCollectionBuilder AddCoreMappers()
{
Add<AccessMapper>();
Add<AuditItemMapper>();
@@ -11,7 +11,6 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// <summary>
/// Represents an SqlSyntaxProvider for MySql
/// </summary>
[SqlSyntaxProvider(Constants.DbProviderNames.MySql)]
public class MySqlSyntaxProvider : SqlSyntaxProviderBase<MySqlSyntaxProvider>
{
private readonly ILogger _logger;
@@ -334,7 +333,7 @@ ORDER BY TABLE_NAME, INDEX_NAME",
switch (systemMethod)
{
case SystemMethods.NewGuid:
return null; // NOT SUPPORTED!
return null; // NOT SUPPORTED!
case SystemMethods.CurrentDateTime:
return "CURRENT_TIMESTAMP";
}
@@ -4,14 +4,12 @@ using System.Linq;
using NPoco;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Represents an SqlSyntaxProvider for Sql Ce
/// </summary>
[SqlSyntaxProvider(Constants.DbProviderNames.SqlCe)]
public class SqlCeSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlCeSyntaxProvider>
{
public override Sql<ISqlContext> SelectTop(Sql<ISqlContext> sql, int top)
@@ -11,29 +11,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// <summary>
/// Represents an SqlSyntaxProvider for Sql Server.
/// </summary>
[SqlSyntaxProvider(Constants.DbProviderNames.SqlServer)]
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlServerSyntaxProvider>
{
// IUmbracoDatabaseFactory to be lazily injected
public SqlServerSyntaxProvider(Lazy<IScopeProvider> lazyScopeProvider)
{
_serverVersion = new Lazy<ServerVersionInfo>(() =>
{
var scopeProvider = lazyScopeProvider.Value;
if (scopeProvider == null)
throw new InvalidOperationException("Failed to determine Sql Server version (no scope provider).");
using (var scope = scopeProvider.CreateScope())
{
var version = DetermineVersion(scope.Database);
scope.Complete();
return version;
}
});
}
private readonly Lazy<ServerVersionInfo> _serverVersion;
internal ServerVersionInfo ServerVersion => _serverVersion.Value;
internal ServerVersionInfo ServerVersion { get; private set; }
internal enum VersionName
{
@@ -62,19 +42,31 @@ namespace Umbraco.Core.Persistence.SqlSyntax
internal class ServerVersionInfo
{
public string Edition { get; set; }
public string InstanceName { get; set; }
public string ProductVersion { get; set; }
public VersionName ProductVersionName { get; private set; }
public EngineEdition EngineEdition { get; set; }
public bool IsAzure => EngineEdition == EngineEdition.Azure;
public string MachineName { get; set; }
public string ProductLevel { get; set; }
public void Initialize()
public ServerVersionInfo()
{
ProductVersionName = MapProductVersion(ProductVersion);
ProductVersionName = VersionName.Unknown;
EngineEdition = EngineEdition.Unknown;
}
public ServerVersionInfo(string edition, string instanceName, string productVersion, EngineEdition engineEdition, string machineName, string productLevel)
{
Edition = edition;
InstanceName = instanceName;
ProductVersion = productVersion;
ProductVersionName = MapProductVersion(ProductVersion);
EngineEdition = engineEdition;
MachineName = machineName;
ProductLevel = productLevel;
}
public string Edition { get; }
public string InstanceName { get; }
public string ProductVersion { get; }
public VersionName ProductVersionName { get; }
public EngineEdition EngineEdition { get; }
public bool IsAzure => EngineEdition == EngineEdition.Azure;
public string MachineName { get; }
public string ProductLevel { get; }
}
private static VersionName MapProductVersion(string productVersion)
@@ -105,8 +97,14 @@ namespace Umbraco.Core.Persistence.SqlSyntax
}
}
private static ServerVersionInfo DetermineVersion(IUmbracoDatabase database)
internal ServerVersionInfo GetSetVersion(string connectionString, string providerName)
{
var factory = DbProviderFactories.GetFactory(providerName);
var connection = factory.CreateConnection();
if (connection == null)
throw new InvalidOperationException($"Could not create a connection for provider \"{providerName}\".");
// Edition: "Express Edition", "Windows Azure SQL Database..."
// EngineEdition: 1/Desktop 2/Standard 3/Enterprise 4/Express 5/Azure
// ProductLevel: RTM, SPx, CTP...
@@ -123,44 +121,28 @@ namespace Umbraco.Core.Persistence.SqlSyntax
SERVERPROPERTY('ResourceLastUpdateDateTime') ResourceLastUpdateDateTime,
SERVERPROPERTY('ProductLevel') ProductLevel;";
try
{
var version = database.Fetch<ServerVersionInfo>(sql).First();
version.Initialize();
return version;
}
catch (Exception e)
{
// can't ignore, really
throw new Exception("Failed to determine Sql Server version (see inner exception).", e);
}
}
internal static VersionName GetVersionName(string connectionString, string providerName)
{
var factory = DbProviderFactories.GetFactory(providerName);
var connection = factory.CreateConnection();
if (connection == null)
throw new InvalidOperationException($"Could not create a connection for provider \"{providerName}\".");
connection.ConnectionString = connectionString;
ServerVersionInfo version;
using (connection)
{
try
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "SELECT SERVERPROPERTY('ProductVersion');";
var productVersion = command.ExecuteScalar().ToString();
command.CommandText = sql;
using (var reader = command.ExecuteReader())
{
version = new ServerVersionInfo(reader.GetString(0), reader.GetString(2), reader.GetString(3), (EngineEdition) reader.GetInt32(5), reader.GetString(7), reader.GetString(9));
}
connection.Close();
return MapProductVersion(productVersion);
}
catch
{
return VersionName.Unknown;
version = new ServerVersionInfo(); // all unknown
}
}
return ServerVersion = version;
}
/// <summary>
@@ -1,21 +0,0 @@
using System;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Attribute for implementations of an ISqlSyntaxProvider
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SqlSyntaxProviderAttribute : Attribute
{
public SqlSyntaxProviderAttribute(string providerName)
{
ProviderName = providerName;
}
/// <summary>
/// Gets or sets the ProviderName that corresponds to the sql syntax in a provider.
/// </summary>
public string ProviderName { get; set; }
}
}
@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Common;
using System.Linq;
using System.Threading;
using NPoco;
using NPoco.FluentMappings;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Persistence.FaultHandling;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -27,12 +24,11 @@ namespace Umbraco.Core.Persistence
/// </remarks>
internal class UmbracoDatabaseFactory : DisposableObject, IUmbracoDatabaseFactory
{
private readonly ISqlSyntaxProvider[] _sqlSyntaxProviders;
private readonly IMapperCollection _mappers;
private readonly Lazy<IMapperCollection> _mappers;
private readonly ILogger _logger;
private readonly SqlContext _sqlContext = new SqlContext();
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private SqlContext _sqlContext;
private DatabaseFactory _npocoDatabaseFactory;
private IPocoDataFactory _pocoDataFactory;
private string _connectionString;
@@ -51,24 +47,20 @@ namespace Umbraco.Core.Persistence
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoDatabaseFactory"/>.
/// </summary>
/// <remarks>Used by injection.</remarks>
public UmbracoDatabaseFactory(IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IMapperCollection mappers)
: this(Constants.System.UmbracoConnectionName, sqlSyntaxProviders, logger, mappers)
{
if (Configured == false)
DatabaseBuilder.GiveLegacyAChance(this, logger);
}
/// <remarks>Used by core runtime.</remarks>
public UmbracoDatabaseFactory(ILogger logger, Lazy<IMapperCollection> mappers)
: this(Constants.System.UmbracoConnectionName, logger, mappers)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoDatabaseFactory"/>.
/// </summary>
/// <remarks>Used by the other ctor and in tests.</remarks>
public UmbracoDatabaseFactory(string connectionStringName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IMapperCollection mappers)
public UmbracoDatabaseFactory(string connectionStringName, ILogger logger, Lazy<IMapperCollection> mappers)
{
if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentNullOrEmptyException(nameof(connectionStringName));
_mappers = mappers ?? throw new ArgumentNullException(nameof(mappers));
_sqlSyntaxProviders = sqlSyntaxProviders?.ToArray() ?? throw new ArgumentNullException(nameof(sqlSyntaxProviders));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
var settings = ConfigurationManager.ConnectionStrings[connectionStringName];
@@ -92,10 +84,9 @@ namespace Umbraco.Core.Persistence
/// Initializes a new instance of the <see cref="UmbracoDatabaseFactory"/>.
/// </summary>
/// <remarks>Used in tests.</remarks>
public UmbracoDatabaseFactory(string connectionString, string providerName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IMapperCollection mappers)
public UmbracoDatabaseFactory(string connectionString, string providerName, ILogger logger, Lazy<IMapperCollection> mappers)
{
_mappers = mappers ?? throw new ArgumentNullException(nameof(mappers));
_sqlSyntaxProviders = sqlSyntaxProviders?.ToArray() ?? throw new ArgumentNullException(nameof(sqlSyntaxProviders));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName))
@@ -139,7 +130,7 @@ namespace Umbraco.Core.Persistence
if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.")
|| !Enum<SqlServerSyntaxProvider.VersionName>.TryParse(setting.Substring("SqlServer.".Length), out var versionName, true))
{
versionName = SqlServerSyntaxProvider.GetVersionName(_connectionString, _providerName);
versionName = ((SqlServerSyntaxProvider) _sqlSyntax).GetSetVersion(_connectionString, _providerName).ProductVersionName;
}
else
{
@@ -165,7 +156,7 @@ namespace Umbraco.Core.Persistence
}
/// <inheritdoc />
public ISqlContext SqlContext => _sqlContext;
public ISqlContext SqlContext => _sqlContext ?? (_sqlContext = new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers.Value));
/// <inheritdoc />
public void ConfigureForUpgrade()
@@ -218,10 +209,6 @@ namespace Umbraco.Core.Persistence
if (_npocoDatabaseFactory == null) throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance.");
// can initialize now because it is the UmbracoDatabaseFactory that determines
// the sql syntax, poco data factory, and database type
_sqlContext.Initialize(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers);
_logger.Debug<UmbracoDatabaseFactory>("Configured.");
Configured = true;
}
@@ -245,17 +232,17 @@ namespace Umbraco.Core.Persistence
// gets the sql syntax provider that corresponds, from attribute
private ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName)
{
var name = providerName.ToLowerInvariant();
var provider = _sqlSyntaxProviders.FirstOrDefault(x =>
x.GetType()
.FirstAttribute<SqlSyntaxProviderAttribute>()
.ProviderName.ToLowerInvariant()
.Equals(name));
if (provider != null) return provider;
throw new InvalidOperationException($"Unknown provider name \"{providerName}\"");
// previously we'd try to return SqlServerSyntaxProvider by default but this is bad
//provider = _syntaxProviders.FirstOrDefault(x => x.GetType() == typeof(SqlServerSyntaxProvider));
switch (providerName)
{
case Constants.DbProviderNames.MySql:
return new MySqlSyntaxProvider(_logger);
case Constants.DbProviderNames.SqlCe:
return new SqlCeSyntaxProvider();
case Constants.DbProviderNames.SqlServer:
return new SqlServerSyntaxProvider();
default:
throw new InvalidOperationException($"Unknown provider name \"{providerName}\"");
}
}
// ensures that the database is configured, else throws
@@ -277,7 +264,7 @@ namespace Umbraco.Core.Persistence
// method used by NPoco's UmbracoDatabaseFactory to actually create the database instance
private UmbracoDatabase CreateDatabaseInstance()
{
return new UmbracoDatabase(_connectionString, _sqlContext, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
return new UmbracoDatabase(_connectionString, SqlContext, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
}
protected override void DisposeResources()
@@ -4,10 +4,6 @@ namespace Umbraco.Core.PropertyEditors
{
public class DataEditorCollectionBuilder : LazyCollectionBuilderBase<DataEditorCollectionBuilder, DataEditorCollection, IDataEditor>
{
public DataEditorCollectionBuilder(IContainer container)
: base(container)
{ }
protected override DataEditorCollectionBuilder This => this;
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Core.PropertyEditors
{
internal class ManifestValueValidatorCollectionBuilder : LazyCollectionBuilderBase<ManifestValueValidatorCollectionBuilder, ManifestValueValidatorCollection, IManifestValueValidator>
{
public ManifestValueValidatorCollectionBuilder(IContainer container)
: base(container)
{ }
protected override ManifestValueValidatorCollectionBuilder This => this;
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Core.PropertyEditors
{
public class PropertyValueConverterCollectionBuilder : OrderedCollectionBuilderBase<PropertyValueConverterCollectionBuilder, PropertyValueConverterCollection, IPropertyValueConverter>
{
public PropertyValueConverterCollectionBuilder(IContainer container)
: base(container)
{ }
protected override PropertyValueConverterCollectionBuilder This => this;
}
}
+156 -135
View File
@@ -15,9 +15,9 @@ using Umbraco.Core.Logging.Serilog;
using Umbraco.Core.Migrations.Upgrade;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services.Implement;
using Umbraco.Core.Sync;
namespace Umbraco.Core.Runtime
{
@@ -28,39 +28,71 @@ namespace Umbraco.Core.Runtime
/// should be possible to use this runtime in console apps.</remarks>
public class CoreRuntime : IRuntime
{
private BootLoader _bootLoader;
private Components.Components _components;
private RuntimeState _state;
/// <summary>
/// Gets the logger.
/// </summary>
protected ILogger Logger { get; private set; }
/// <summary>
/// Gets the profiling logger.
/// </summary>
protected IProfilingLogger ProfilingLogger { get; private set; }
/// <inheritdoc/>
public virtual void Boot(IContainer container)
{
// assign current container
Current.Container = container;
// register the essential stuff,
// ie the global application logger
// (profiler etc depend on boot manager)
// create and register the essential services
// ie the bare minimum required to boot
var composition = new Composition(container, RuntimeLevel.Boot);
// loggers
var logger = GetLogger();
container.RegisterInstance(logger);
// now it is ok to use Current.Logger
Logger = logger;
var profiler = GetProfiler();
container.RegisterInstance(profiler);
var profilingLogger = new ProfilingLogger(logger, profiler);
container.RegisterInstance<IProfilingLogger>(profilingLogger);
ProfilingLogger = profilingLogger;
ConfigureUnhandledException(logger);
ConfigureAssemblyResolve(logger);
// application environment
ConfigureUnhandledException();
ConfigureAssemblyResolve();
ConfigureApplicationRootPath();
Compose(container);
// application caches
var appCaches = GetAppCaches();
container.RegisterInstance(appCaches);
var runtimeCache = appCaches.RuntimeCache;
container.RegisterInstance(runtimeCache);
// prepare essential stuff
// database factory
var databaseFactory = new UmbracoDatabaseFactory(logger, new Lazy<IMapperCollection>(container.GetInstance<IMapperCollection>));
container.RegisterSingleton(factory => factory.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
var path = GetApplicationRootPath();
if (string.IsNullOrWhiteSpace(path) == false)
IOHelper.SetRootDirectory(path);
// type loader
var globalSettings = UmbracoConfig.For.GlobalSettings();
var typeLoader = new TypeLoader(runtimeCache, globalSettings, profilingLogger);
container.RegisterInstance(typeLoader);
_state = (RuntimeState) container.GetInstance<IRuntimeState>();
_state.Level = RuntimeLevel.Boot;
// runtime state
_state = new RuntimeState(logger,
UmbracoConfig.For.UmbracoSettings(), UmbracoConfig.For.GlobalSettings(),
new Lazy<MainDom>(container.GetInstance<MainDom>),
new Lazy<IServerRegistrar>(container.GetInstance<IServerRegistrar>))
{
Level = RuntimeLevel.Boot
};
container.RegisterInstance(_state);
Logger = container.GetInstance<ILogger>();
Profiler = container.GetInstance<IProfiler>();
ProfilingLogger = container.GetInstance<ProfilingLogger>();
Compose(composition);
// 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.
@@ -76,18 +108,33 @@ namespace Umbraco.Core.Runtime
"Booted.",
"Boot failed."))
{
// throws if not full-trust
new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand();
try
{
Logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
// throws if not full-trust
new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand();
AquireMainDom(container);
DetermineRuntimeLevel(container);
var componentTypes = ResolveComponentTypes();
_bootLoader = new BootLoader(container);
_bootLoader.Boot(componentTypes, _state.Level);
logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
var mainDom = AquireMainDom();
container.RegisterInstance(mainDom);
DetermineRuntimeLevel(databaseFactory);
var componentTypes = ResolveComponentTypes(typeLoader);
_components = new Components.Components(composition, componentTypes, profilingLogger);
_components.Compose();
// no Current.Container only Current.Factory?
//factory = register.Compile();
// fixme at that point we can start actually getting things from the container
// but, ideally, not before = need to detect everything we use!!
// at that point, getting things from the container is ok
// fixme split IRegistry vs IFactory
_components.Initialize();
}
catch (Exception e)
{
@@ -105,15 +152,7 @@ namespace Umbraco.Core.Runtime
}
}
/// <summary>
/// Gets a logger.
/// </summary>
protected virtual ILogger GetLogger()
{
return SerilogLogger.CreateWithDefaultConfiguration();
}
protected virtual void ConfigureUnhandledException(ILogger logger)
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
@@ -126,33 +165,40 @@ namespace Umbraco.Core.Runtime
var msg = "Unhandled exception in AppDomain";
if (isTerminating) msg += " (terminating)";
msg += ".";
logger.Error<CoreRuntime>(exception, msg);
Logger.Error<CoreRuntime>(exception, msg);
};
}
protected virtual void ConfigureAssemblyResolve(ILogger logger)
protected virtual void ConfigureAssemblyResolve()
{
// When an assembly can't be resolved. In here we can do magic with the assembly name and try loading another.
// This is used for loading a signed assembly of AutoMapper (v. 3.1+) without having to recompile old code.
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stack overflow
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
return null;
};
}
private void AquireMainDom(IContainer container)
protected virtual void ConfigureApplicationRootPath()
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Aquired."))
var path = GetApplicationRootPath();
if (string.IsNullOrWhiteSpace(path) == false)
IOHelper.SetRootDirectory(path);
}
private MainDom AquireMainDom()
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
var mainDom = container.GetInstance<MainDom>();
var mainDom = new MainDom(Logger);
mainDom.Acquire();
return mainDom;
}
catch
{
@@ -163,38 +209,38 @@ namespace Umbraco.Core.Runtime
}
// internal for tests
internal void DetermineRuntimeLevel(IContainer container)
internal void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory)
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Determining runtime level.", "Determined."))
{
try
{
var dbfactory = container.GetInstance<IUmbracoDatabaseFactory>();
SetRuntimeStateLevel(dbfactory, Logger);
_state.Level = DetermineRuntimeLevel2(databaseFactory);
Logger.Debug<CoreRuntime>("Runtime level: {RuntimeLevel}", _state.Level);
ProfilingLogger.Debug<CoreRuntime>("Runtime level: {RuntimeLevel}", _state.Level);
if (_state.Level == RuntimeLevel.Upgrade)
{
Logger.Debug<CoreRuntime>("Configure database factory for upgrades.");
dbfactory.ConfigureForUpgrade();
ProfilingLogger.Debug<CoreRuntime>("Configure database factory for upgrades.");
databaseFactory.ConfigureForUpgrade();
}
}
catch
{
_state.Level = RuntimeLevel.BootFailed;
timer.Fail();
throw;
}
}
}
private IEnumerable<Type> ResolveComponentTypes()
private IEnumerable<Type> ResolveComponentTypes(TypeLoader typeLoader)
{
using (var timer = ProfilingLogger.TraceDuration<CoreRuntime>("Resolving component types.", "Resolved."))
{
try
{
return GetComponentTypes();
return GetComponentTypes(typeLoader);
}
catch
{
@@ -209,97 +255,56 @@ namespace Umbraco.Core.Runtime
{
using (ProfilingLogger.DebugDuration<CoreRuntime>("Terminating Umbraco.", "Terminated."))
{
_bootLoader?.Terminate();
_components?.Terminate();
}
}
/// <summary>
/// Composes the runtime.
/// </summary>
public virtual void Compose(IContainer container)
public virtual void Compose(Composition composition)
{
var container = composition.Container;
// compose the very essential things that are needed to bootstrap, before anything else,
// and only these things - the rest should be composed in runtime components
// register basic things
container.RegisterSingleton<IProfiler, LogProfiler>();
container.RegisterSingleton<ProfilingLogger>();
container.RegisterSingleton<IRuntimeState, RuntimeState>();
// FIXME should be essentially empty! move all to component!
container.ComposeConfiguration();
// register caches
// need the deep clone runtime cache profiver to ensure entities are cached properly, ie
// are cloned in and cloned out - no request-based cache here since no web-based context,
// will be overriden later or
container.RegisterSingleton(_ => new CacheHelper(
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()),
new StaticCacheProvider(),
NullCacheProvider.Instance,
new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))));
container.RegisterSingleton(f => f.GetInstance<CacheHelper>().RuntimeCache);
// register the plugin manager
container.RegisterSingleton(f => new TypeLoader(f.GetInstance<IRuntimeCacheProvider>(), f.GetInstance<IGlobalSettings>(), f.GetInstance<ProfilingLogger>()));
// register syntax providers - required by database factory - GetAllInstances<ISqlSyntaxProvider> or an IEnumerable can get them
container.Register<MySqlSyntaxProvider>();
container.Register<SqlCeSyntaxProvider>();
container.Register<SqlServerSyntaxProvider>();
// 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
var mapperCollectionBuilder = container.RegisterCollectionBuilder<MapperCollectionBuilder>();
ComposeMapperCollection(mapperCollectionBuilder);
// register database factory - required to check for migrations
// will be initialized with syntax providers and a logger, and will try to configure
// from the default connection string name, if possible, else will remain non-configured
// until properly configured (eg when installing)
container.RegisterSingleton<IUmbracoDatabaseFactory, UmbracoDatabaseFactory>();
container.RegisterSingleton(f => f.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
composition.GetCollectionBuilder<MapperCollectionBuilder>().AddCoreMappers();
// register the scope provider
container.RegisterSingleton<ScopeProvider>(); // implements both IScopeProvider and IScopeAccessor
container.RegisterSingleton<IScopeProvider>(f => f.GetInstance<ScopeProvider>());
container.RegisterSingleton<IScopeAccessor>(f => f.GetInstance<ScopeProvider>());
// register MainDom
container.RegisterSingleton<MainDom>();
}
protected virtual void ComposeMapperCollection(MapperCollectionBuilder builder)
{
builder.AddCore();
}
private void SetRuntimeStateLevel(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
private RuntimeLevel DetermineRuntimeLevel2(IUmbracoDatabaseFactory databaseFactory)
{
var localVersion = UmbracoVersion.LocalVersion; // the local, files, version
var codeVersion = _state.SemanticVersion; // the executing code version
var connect = false;
// we don't know yet
_state.Level = RuntimeLevel.Unknown;
if (localVersion == null)
{
// there is no local version, we are not installed
logger.Debug<CoreRuntime>("No local version, need to install Umbraco.");
_state.Level = RuntimeLevel.Install;
Logger.Debug<CoreRuntime>("No local version, need to install Umbraco.");
return RuntimeLevel.Install;
}
else if (localVersion < codeVersion)
if (localVersion < codeVersion)
{
// there *is* a local version, but it does not match the code version
// need to upgrade
logger.Debug<CoreRuntime>("Local version '{LocalVersion}' < code version '{CodeVersion}', need to upgrade Umbraco.", localVersion, codeVersion);
_state.Level = RuntimeLevel.Upgrade;
Logger.Debug<CoreRuntime>("Local version '{LocalVersion}' < code version '{CodeVersion}', need to upgrade Umbraco.", localVersion, codeVersion);
}
else if (localVersion > codeVersion)
{
logger.Warn<CoreRuntime>("Local version '{LocalVersion}' > code version '{CodeVersion}', downgrading is not supported.", localVersion, codeVersion);
_state.Level = RuntimeLevel.BootFailed;
Logger.Warn<CoreRuntime>("Local version '{LocalVersion}' > code version '{CodeVersion}', downgrading is not supported.", localVersion, codeVersion);
// in fact, this is bad enough that we want to throw
throw new BootFailedException($"Local version \"{localVersion}\" > code version \"{codeVersion}\", downgrading is not supported.");
@@ -308,14 +313,10 @@ namespace Umbraco.Core.Runtime
{
// local version *does* match code version, but the database is not configured
// install (again? this is a weird situation...)
logger.Debug<CoreRuntime>("Database is not configured, need to install Umbraco.");
_state.Level = RuntimeLevel.Install;
Logger.Debug<CoreRuntime>("Database is not configured, need to install Umbraco.");
return RuntimeLevel.Install;
}
// install? not going to test anything else
if (_state.Level == RuntimeLevel.Install)
return;
// else, keep going,
// anything other than install wants a database - see if we can connect
// (since this is an already existing database, assume localdb is ready)
@@ -323,15 +324,14 @@ namespace Umbraco.Core.Runtime
{
connect = databaseFactory.CanConnect;
if (connect) break;
logger.Debug<CoreRuntime>("Could not immediately connect to database, trying again.");
Logger.Debug<CoreRuntime>("Could not immediately connect to database, trying again.");
Thread.Sleep(1000);
}
if (connect == false)
{
// cannot connect to configured database, this is bad, fail
logger.Debug<CoreRuntime>("Could not connect to database.");
_state.Level = RuntimeLevel.BootFailed;
Logger.Debug<CoreRuntime>("Could not connect to database.");
// in fact, this is bad enough that we want to throw
throw new BootFailedException("A connection string is configured but Umbraco could not connect to the database.");
@@ -347,20 +347,19 @@ namespace Umbraco.Core.Runtime
bool noUpgrade;
try
{
noUpgrade = EnsureUmbracoUpgradeState(databaseFactory, logger);
noUpgrade = EnsureUmbracoUpgradeState(databaseFactory);
}
catch (Exception e)
{
// can connect to the database but cannot check the upgrade state... oops
logger.Warn<CoreRuntime>(e, "Could not check the upgrade state.");
Logger.Warn<CoreRuntime>(e, "Could not check the upgrade state.");
throw new BootFailedException("Could not check the upgrade state.", e);
}
if (noUpgrade)
{
// the database version matches the code & files version, all clear, can run
_state.Level = RuntimeLevel.Run;
return;
return RuntimeLevel.Run;
}
// the db version does not match... but we do have a migration table
@@ -368,11 +367,11 @@ namespace Umbraco.Core.Runtime
// although the files version matches the code version, the database version does not
// which means the local files have been upgraded but not the database - need to upgrade
logger.Debug<CoreRuntime>("Has not reached the final upgrade step, need to upgrade Umbraco.");
_state.Level = RuntimeLevel.Upgrade;
Logger.Debug<CoreRuntime>("Has not reached the final upgrade step, need to upgrade Umbraco.");
return RuntimeLevel.Upgrade;
}
protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory)
{
var umbracoPlan = new UmbracoPlan();
var stateValueKey = Upgrader.GetStateValueKey(umbracoPlan);
@@ -384,31 +383,53 @@ namespace Umbraco.Core.Runtime
_state.FinalMigrationState = umbracoPlan.FinalState;
}
logger.Debug<CoreRuntime>("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", _state.FinalMigrationState, _state.CurrentMigrationState ?? "<null>");
Logger.Debug<CoreRuntime>("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", _state.FinalMigrationState, _state.CurrentMigrationState ?? "<null>");
return _state.CurrentMigrationState == _state.FinalMigrationState;
}
#region Locals
protected ILogger Logger { get; private set; }
protected IProfiler Profiler { get; private set; }
protected ProfilingLogger ProfilingLogger { get; private set; }
#endregion
#region Getters
// getters can be implemented by runtimes inheriting from CoreRuntime
// fixme - inject! no Current!
protected virtual IEnumerable<Type> GetComponentTypes() => Current.TypeLoader.GetTypes<IUmbracoComponent>();
/// <summary>
/// Gets all component types.
/// </summary>
protected virtual IEnumerable<Type> GetComponentTypes(TypeLoader typeLoader)
=> typeLoader.GetTypes<IUmbracoComponent>();
/// <summary>
/// Gets a logger.
/// </summary>
protected virtual ILogger GetLogger()
=> SerilogLogger.CreateWithDefaultConfiguration();
/// <summary>
/// Gets a profiler.
/// </summary>
protected virtual IProfiler GetProfiler()
=> new LogProfiler(ProfilingLogger);
/// <summary>
/// Gets the application caches.
/// </summary>
protected virtual CacheHelper GetAppCaches()
{
// need the deep clone runtime cache provider to ensure entities are cached properly, ie
// are cloned in and cloned out - no request-based cache here since no web-based context,
// is overriden by the web runtime
return new CacheHelper(
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()),
new StaticCacheProvider(),
NullCacheProvider.Instance,
new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())));
}
// by default, returns null, meaning that Umbraco should auto-detect the application root path.
// override and return the absolute path to the Umbraco site/solution, if needed
protected virtual string GetApplicationRootPath() => null;
protected virtual string GetApplicationRootPath()
=> null;
#endregion
}
@@ -47,7 +47,7 @@ namespace Umbraco.Core.Runtime
composition.Container.RegisterSingleton<ManifestParser>();
// register our predefined validators
composition.Container.RegisterCollectionBuilder<ManifestValueValidatorCollectionBuilder>()
composition.GetCollectionBuilder<ManifestValueValidatorCollectionBuilder>()
.Add<RequiredValidator>()
.Add<RegexValidator>()
.Add<DelimitedValueValidator>()
@@ -56,7 +56,7 @@ namespace Umbraco.Core.Runtime
.Add<DecimalValidator>();
// properties and parameters derive from data editors
composition.Container.RegisterCollectionBuilder<DataEditorCollectionBuilder>()
composition.GetCollectionBuilder<DataEditorCollectionBuilder>()
.Add(factory => factory.GetInstance<TypeLoader>().GetDataEditors());
composition.Container.RegisterSingleton<PropertyEditorCollection>();
composition.Container.RegisterSingleton<ParameterEditorCollection>();
@@ -83,13 +83,13 @@ namespace Umbraco.Core.Runtime
factory.GetInstance<IGlobalSettings>(),
true, new DatabaseServerMessengerOptions()));
composition.Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add(factory => factory.GetInstance<TypeLoader>().GetCacheRefreshers());
composition.Container.RegisterCollectionBuilder<PackageActionCollectionBuilder>()
composition.GetCollectionBuilder<PackageActionCollectionBuilder>()
.Add(f => f.GetInstance<TypeLoader>().GetPackageActions());
composition.Container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>()
composition.GetCollectionBuilder<PropertyValueConverterCollectionBuilder>()
.Append(factory => factory.GetInstance<TypeLoader>().GetTypes<IPropertyValueConverter>());
composition.Container.RegisterSingleton<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
@@ -97,10 +97,10 @@ namespace Umbraco.Core.Runtime
composition.Container.RegisterSingleton<IShortStringHelper>(factory
=> new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance<IUmbracoSettingsSection>())));
composition.Container.RegisterCollectionBuilder<UrlSegmentProviderCollectionBuilder>()
composition.GetCollectionBuilder<UrlSegmentProviderCollectionBuilder>()
.Append<DefaultUrlSegmentProvider>();
composition.Container.RegisterCollectionBuilder<PostMigrationCollectionBuilder>()
composition.GetCollectionBuilder<PostMigrationCollectionBuilder>()
.Add(factory => factory.GetInstance<TypeLoader>().GetTypes<IPostMigration>());
composition.Container.RegisterSingleton<IMigrationBuilder>(factory => new MigrationBuilder(composition.Container));
+27 -40
View File
@@ -17,76 +17,67 @@ namespace Umbraco.Core
internal class RuntimeState : IRuntimeState
{
private readonly ILogger _logger;
private readonly Lazy<IServerRegistrar> _serverRegistrar;
private readonly Lazy<MainDom> _mainDom;
private readonly IUmbracoSettingsSection _settings;
private readonly IGlobalSettings _globalSettings;
private readonly HashSet<string> _applicationUrls = new HashSet<string>();
private RuntimeLevel _level;
private Lazy<MainDom> _mainDom;
private Lazy<IServerRegistrar> _serverRegistrar;
/// <summary>
/// Initializes a new instance of the <see cref="RuntimeState"/> class.
/// </summary>
/// <param name="logger">A logger.</param>
/// <param name="serverRegistrar">A (lazy) server registrar.</param>
/// <param name="mainDom">A (lazy) MainDom.</param>
public RuntimeState(ILogger logger, Lazy<IServerRegistrar> serverRegistrar, Lazy<MainDom> mainDom, IUmbracoSettingsSection settings, IGlobalSettings globalSettings)
/// <param name="settings">Umbraco settings.</param>
/// <param name="globalSettings">Global settings.</param>
public RuntimeState(ILogger logger, IUmbracoSettingsSection settings, IGlobalSettings globalSettings,
Lazy<MainDom> mainDom, Lazy<IServerRegistrar> serverRegistrar)
{
_logger = logger;
_serverRegistrar = serverRegistrar;
_mainDom = mainDom;
_settings = settings;
_globalSettings = globalSettings;
_mainDom = mainDom;
_serverRegistrar = serverRegistrar;
}
/// <summary>
/// Gets the server registrar.
/// </summary>
/// <remarks>
/// <para>This is NOT exposed in the interface.</para>
/// </remarks>
private IServerRegistrar ServerRegistrar => _serverRegistrar.Value;
/// <summary>
/// Gets the application MainDom.
/// </summary>
/// <remarks>This is NOT exposed in the interface as MainDom is internal.</remarks>
/// <remarks>
/// <para>This is NOT exposed in the interface as MainDom is internal.</para>
/// </remarks>
public MainDom MainDom => _mainDom.Value;
/// <summary>
/// Gets the version of the executing code.
/// </summary>
/// <inheritdoc />
public Version Version => UmbracoVersion.Current;
/// <summary>
/// Gets the version comment of the executing code.
/// </summary>
/// <inheritdoc />
public string VersionComment => UmbracoVersion.Comment;
/// <summary>
/// Gets the semantic version of the executing code.
/// </summary>
/// <inheritdoc />
public SemVersion SemanticVersion => UmbracoVersion.SemanticVersion;
/// <summary>
/// Gets a value indicating whether the application is running in debug mode.
/// </summary>
/// <inheritdoc />
public bool Debug { get; } = GlobalSettings.DebugMode;
/// <summary>
/// Gets a value indicating whether the runtime is the current main domain.
/// </summary>
/// <inheritdoc />
public bool IsMainDom => MainDom.IsMainDom;
/// <summary>
/// Get the server's current role.
/// </summary>
/// <inheritdoc />
public ServerRole ServerRole => ServerRegistrar.GetCurrentServerRole();
/// <summary>
/// Gets the Umbraco application url.
/// </summary>
/// <remarks>This is eg "http://www.example.com".</remarks>
/// <inheritdoc />
public Uri ApplicationUrl { get; private set; }
/// <summary>
/// Gets the Umbraco application virtual path.
/// </summary>
/// <remarks>This is either "/" or eg "/virtual".</remarks>
/// <inheritdoc />
public string ApplicationVirtualPath { get; } = HttpRuntime.AppDomainAppVirtualPath;
/// <inheritdoc />
@@ -95,9 +86,7 @@ namespace Umbraco.Core
/// <inheritdoc />
public string FinalMigrationState { get; internal set; }
/// <summary>
/// Gets the runtime level of execution.
/// </summary>
/// <inheritdoc />
public RuntimeLevel Level
{
get => _level;
@@ -137,9 +126,7 @@ namespace Umbraco.Core
return _runLevel.WaitHandle.WaitOne(timeout);
}
/// <summary>
/// Gets the exception that caused the boot to fail.
/// </summary>
/// <inheritdoc />
public BootFailedException BootFailedException { get; internal set; }
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Core.Strings
{
public class UrlSegmentProviderCollectionBuilder : OrderedCollectionBuilderBase<UrlSegmentProviderCollectionBuilder, UrlSegmentProviderCollection, IUrlSegmentProvider>
{
public UrlSegmentProviderCollectionBuilder(IContainer container)
: base(container)
{ }
protected override UrlSegmentProviderCollectionBuilder This => this;
}
}
+2 -2
View File
@@ -155,7 +155,7 @@
<Compile Include="Collections\ListCloneBehavior.cs" />
<Compile Include="Collections\ObservableDictionary.cs" />
<Compile Include="Collections\TypeList.cs" />
<Compile Include="Components\BootLoader.cs" />
<Compile Include="Components\Components.cs" />
<Compile Include="Components\Composition.cs" />
<Compile Include="Components\CompositionExtensions.cs" />
<Compile Include="Components\DisableComponentAttribute.cs" />
@@ -335,6 +335,7 @@
<Compile Include="IO\MediaPathSchemes\OriginalMediaPathScheme.cs" />
<Compile Include="IO\MediaPathSchemes\TwoGuidsMediaPathScheme.cs" />
<Compile Include="KeyValuePairExtensions.cs" />
<Compile Include="Logging\IProfilingLogger.cs" />
<Compile Include="Logging\LogHttpRequest.cs" />
<Compile Include="Logging\LogLevel.cs" />
<Compile Include="Logging\MessageTemplates.cs" />
@@ -1222,7 +1223,6 @@
<Compile Include="Persistence\SqlSyntax\SqlCeSyntaxProvider.cs" />
<Compile Include="Persistence\SqlSyntax\SqlServerSyntaxProvider.cs" />
<Compile Include="Persistence\SqlSyntax\SqlServerVersionName.cs" />
<Compile Include="Persistence\SqlSyntax\SqlSyntaxProviderAttribute.cs" />
<Compile Include="Persistence\SqlSyntax\SqlSyntaxProviderBase.cs" />
<Compile Include="Persistence\SqlSyntax\SqlSyntaxProviderExtensions.cs" />
<Compile Include="Persistence\SqlTemplate.cs" />
@@ -4,10 +4,6 @@ namespace Umbraco.Core._Legacy.PackageActions
{
internal class PackageActionCollectionBuilder : LazyCollectionBuilderBase<PackageActionCollectionBuilder, PackageActionCollection, IPackageAction>
{
public PackageActionCollectionBuilder(IContainer container)
: base(container)
{ }
protected override PackageActionCollectionBuilder This => this;
}
}
@@ -4,18 +4,12 @@ using System.Data.SqlServerCe;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Horology;
using BenchmarkDotNet.Jobs;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;
using Umbraco.Tests.Benchmarks.Config;
using Umbraco.Tests.TestHelpers;
@@ -34,13 +28,11 @@ namespace Umbraco.Tests.Benchmarks
{
IScopeProvider f = null;
var l = new Lazy<IScopeProvider>(() => f);
var p = new SqlServerSyntaxProvider(l);
var factory = new UmbracoDatabaseFactory(
"server=.\\SQLExpress;database=YOURDB;user id=YOURUSER;password=YOURPASS",
Constants.DatabaseProviders.SqlServer,
new [] { p },
logger,
new MapperCollection(Enumerable.Empty<BaseMapper>()));
new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())));
return factory.CreateDatabase();
}
@@ -49,9 +41,8 @@ namespace Umbraco.Tests.Benchmarks
var f = new UmbracoDatabaseFactory(
cstr,
Constants.DatabaseProviders.SqlCe,
new[] { new SqlCeSyntaxProvider() },
logger,
new MapperCollection(Enumerable.Empty<BaseMapper>()));
new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())));
return f.CreateDatabase();
}
@@ -4,6 +4,7 @@ using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Sync;
@@ -21,11 +22,12 @@ namespace Umbraco.Tests.Cache.DistributedCache
public void Setup()
{
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
container.Register<IServerRegistrar>(_ => new TestServerRegistrar());
container.RegisterSingleton<IServerMessenger>(_ => new TestServerMessenger());
container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add<TestCacheRefresher>();
_distributedCache = new Umbraco.Web.Cache.DistributedCache();
@@ -29,7 +29,7 @@ namespace Umbraco.Tests.Cache.PublishedCache
{
base.Compose();
Container.GetInstance<UrlSegmentProviderCollectionBuilder>()
Composition.GetCollectionBuilder<UrlSegmentProviderCollectionBuilder>()
.Clear()
.Append<DefaultUrlSegmentProvider>();
}
+60 -33
View File
@@ -27,10 +27,8 @@ namespace Umbraco.Tests.Components
var mock = new Mock<IContainer>();
var testObjects = new TestObjects(null);
var logger = Mock.Of<ILogger>();
var s = testObjects.GetDefaultSqlSyntaxProviders(logger);
var f = new UmbracoDatabaseFactory(s, logger, new MapperCollection(Enumerable.Empty<BaseMapper>()));
var f = new UmbracoDatabaseFactory(logger, new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())));
var fs = new FileSystems(mock.Object, logger);
var p = new ScopeProvider(f, fs, logger);
@@ -47,13 +45,15 @@ namespace Umbraco.Tests.Components
public void Boot1A()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var loader = new BootLoader(container);
var types = TypeArray<Component1, Component2, Component3, Component4>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
// 2 is Core and requires 4
// 3 is User - goes away with RuntimeLevel.Unknown
// => reorder components accordingly
loader.Boot(TypeArray<Component1, Component2, Component3, Component4>(), RuntimeLevel.Unknown);
components.Compose();
AssertTypeArray(TypeArray<Component1, Component4, Component2>(), Composed);
}
@@ -61,13 +61,15 @@ namespace Umbraco.Tests.Components
public void Boot1B()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Run);
var loader = new BootLoader(container);
var types = TypeArray<Component1, Component2, Component3, Component4>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
// 2 is Core and requires 4
// 3 is User - stays with RuntimeLevel.Run
// => reorder components accordingly
loader.Boot(TypeArray<Component1, Component2, Component3, Component4>(), RuntimeLevel.Run);
components.Compose();
AssertTypeArray(TypeArray<Component1, Component4, Component2, Component3>(), Composed);
}
@@ -75,12 +77,14 @@ namespace Umbraco.Tests.Components
public void Boot2()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var loader = new BootLoader(container);
var types = TypeArray<Component20, Component21>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
// 21 is required by 20
// => reorder components accordingly
loader.Boot(TypeArray<Component20, Component21>(), RuntimeLevel.Unknown);
components.Compose();
AssertTypeArray(TypeArray<Component21, Component20>(), Composed);
}
@@ -88,14 +92,16 @@ namespace Umbraco.Tests.Components
public void Boot3()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var loader = new BootLoader(container);
var types = TypeArray<Component22, Component24, Component25>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
// i23 requires 22
// 24, 25 implement i23
// 25 required by i23
// => reorder components accordingly
loader.Boot(TypeArray<Component22, Component24, Component25>(), RuntimeLevel.Unknown);
components.Compose();
AssertTypeArray(TypeArray<Component22, Component25, Component24>(), Composed);
}
@@ -103,15 +109,17 @@ namespace Umbraco.Tests.Components
public void BrokenRequire()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = TypeArray<Component1, Component2, Component3>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
try
{
// 2 is Core and requires 4
// 4 is missing
// => throw
thing.Boot(TypeArray < Component1, Component2, Component3>(), RuntimeLevel.Unknown);
components.Compose();
Assert.Fail("Expected exception.");
}
catch (Exception e)
@@ -124,14 +132,16 @@ namespace Umbraco.Tests.Components
public void BrokenRequired()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = TypeArray<Component2, Component4, Component13>();
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
// 2 is Core and requires 4
// 13 is required by 1
// 1 is missing
// => reorder components accordingly
thing.Boot(TypeArray<Component2, Component4, Component13>(), RuntimeLevel.Unknown);
components.Compose();
AssertTypeArray(TypeArray<Component4, Component2, Component13>(), Composed);
}
@@ -142,11 +152,14 @@ namespace Umbraco.Tests.Components
{
m.Setup(x => x.TryGetInstance(It.Is<Type>(t => t == typeof (ISomeResource)))).Returns(() => new SomeResource());
});
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = new[] { typeof(Component1), typeof(Component5) };
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Initialized.Clear();
thing.Boot(new[] { typeof(Component1), typeof(Component5) }, RuntimeLevel.Unknown);
components.Compose();
components.Initialize();
Assert.AreEqual(2, Composed.Count);
Assert.AreEqual(typeof(Component1), Composed[0]);
Assert.AreEqual(typeof(Component5), Composed[1]);
@@ -158,10 +171,12 @@ namespace Umbraco.Tests.Components
public void Requires1()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = new[] { typeof(Component6), typeof(Component7), typeof(Component8) };
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component6), typeof(Component7), typeof(Component8) }, RuntimeLevel.Unknown);
components.Compose();
Assert.AreEqual(2, Composed.Count);
Assert.AreEqual(typeof(Component6), Composed[0]);
Assert.AreEqual(typeof(Component8), Composed[1]);
@@ -171,10 +186,12 @@ namespace Umbraco.Tests.Components
public void Requires2A()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = new[] { typeof(Component9), typeof(Component2), typeof(Component4) };
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component9), typeof(Component2), typeof(Component4) }, RuntimeLevel.Unknown);
components.Compose();
Assert.AreEqual(2, Composed.Count);
Assert.AreEqual(typeof(Component4), Composed[0]);
Assert.AreEqual(typeof(Component2), Composed[1]);
@@ -185,10 +202,13 @@ namespace Umbraco.Tests.Components
public void Requires2B()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Run);
var thing = new BootLoader(container);
var types = new[] { typeof(Component9), typeof(Component2), typeof(Component4) };
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component9), typeof(Component2), typeof(Component4) }, RuntimeLevel.Run);
components.Compose();
components.Initialize();
Assert.AreEqual(3, Composed.Count);
Assert.AreEqual(typeof(Component4), Composed[0]);
Assert.AreEqual(typeof(Component2), Composed[1]);
@@ -199,24 +219,29 @@ namespace Umbraco.Tests.Components
public void WeakDependencies()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = new[] { typeof(Component10) };
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component10) }, RuntimeLevel.Unknown);
components.Compose();
Assert.AreEqual(1, Composed.Count);
Assert.AreEqual(typeof(Component10), Composed[0]);
thing = new BootLoader(container);
types = new[] { typeof(Component11) };
components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => thing.Boot(new[] { typeof(Component11) }, RuntimeLevel.Unknown));
Assert.Throws<Exception>(() => components.Compose());
thing = new BootLoader(container);
types = new[] { typeof(Component2) };
components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => thing.Boot(new[] { typeof(Component2) }, RuntimeLevel.Unknown));
Assert.Throws<Exception>(() => components.Compose());
thing = new BootLoader(container);
types = new[] { typeof(Component12) };
components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component12) }, RuntimeLevel.Unknown);
components.Compose();
Assert.AreEqual(1, Composed.Count);
Assert.AreEqual(typeof(Component12), Composed[0]);
}
@@ -225,10 +250,12 @@ namespace Umbraco.Tests.Components
public void DisableMissing()
{
var container = MockContainer();
var composition = new Composition(container, RuntimeLevel.Unknown);
var thing = new BootLoader(container);
var types = new[] { typeof(Component6), typeof(Component8) }; // 8 disables 7 which is not in the list
var components = new Core.Components.Components(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
thing.Boot(new[] { typeof(Component6), typeof(Component8) }, RuntimeLevel.Unknown); // 8 disables 7 which is not in the list
components.Compose();
Assert.AreEqual(2, Composed.Count);
Assert.AreEqual(typeof(Component6), Composed[0]);
Assert.AreEqual(typeof(Component8), Composed[1]);
@@ -4,6 +4,7 @@ using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Composing;
using Umbraco.Core;
using Umbraco.Core.Components;
namespace Umbraco.Tests.Composing
{
@@ -11,6 +12,7 @@ namespace Umbraco.Tests.Composing
public class CollectionBuildersTests
{
private IContainer _container;
private Composition _composition;
[SetUp]
public void Setup()
@@ -18,6 +20,7 @@ namespace Umbraco.Tests.Composing
Current.Reset();
_container = Current.Container = ContainerFactory.Create();
_composition = new Composition(_container, RuntimeLevel.Run);
}
[TearDown]
@@ -32,7 +35,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void ContainsTypes()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -48,7 +51,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanClearBuilderBeforeCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -63,7 +66,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotClearBuilderOnceCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -75,7 +78,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanAppendToBuilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>();
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>();
builder.Append<Resolved1>();
builder.Append<Resolved2>();
@@ -90,7 +93,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotAppendToBuilderOnceCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>();
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>();
var col = builder.CreateCollection();
@@ -102,7 +105,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanAppendDuplicateToBuilderAndDeDuplicate()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>();
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>();
builder.Append<Resolved1>();
builder.Append<Resolved1>();
@@ -113,7 +116,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotAppendInvalidTypeToBUilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>();
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>();
//builder.Append<Resolved4>(); // does not compile
Assert.Throws<InvalidOperationException>(() =>
builder.Append(new[] { typeof (Resolved4) }) // throws
@@ -123,7 +126,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanRemoveFromBuilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.Remove<Resolved2>();
@@ -139,7 +142,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanRemoveMissingFromBuilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.Remove<Resolved3>();
@@ -151,7 +154,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotRemoveFromBuilderOnceCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -164,7 +167,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanInsertIntoBuilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.Insert<Resolved3>();
@@ -180,7 +183,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotInsertIntoBuilderOnceCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -193,7 +196,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanInsertDuplicateIntoBuilderAndDeDuplicate()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.Insert<Resolved2>();
@@ -205,7 +208,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanInsertIntoEmptyBuilder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>();
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>();
builder.Insert<Resolved2>();
var col = builder.CreateCollection();
@@ -215,7 +218,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotInsertIntoBuilderAtWrongIndex()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -231,7 +234,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanInsertIntoBuilderBefore()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.InsertBefore<Resolved2, Resolved3>();
@@ -247,7 +250,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotInsertIntoBuilderBeforeOnceCollectionIsCreated()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -260,7 +263,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CanInsertDuplicateIntoBuilderBeforeAndDeDuplicate()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>()
.InsertBefore<Resolved1, Resolved2>();
@@ -272,7 +275,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void CannotInsertIntoBuilderBeforeMissing()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilder>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>();
Assert.Throws<InvalidOperationException>(() =>
@@ -283,7 +286,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void ScopeBuilderCreatesScopedCollection()
{
_container.RegisterCollectionBuilder<TestCollectionBuilder>()
_composition.GetCollectionBuilder<TestCollectionBuilder>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -303,7 +306,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void TransientBuilderCreatesTransientCollection()
{
_container.RegisterCollectionBuilder<TestCollectionBuilderTransient>()
_composition.GetCollectionBuilder<TestCollectionBuilderTransient>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -323,7 +326,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void BuilderRespectsTypesOrder()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilderTransient>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilderTransient>()
.Append<Resolved3>()
.Insert<Resolved1>()
.InsertBefore<Resolved3, Resolved2>();
@@ -335,7 +338,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void ScopeBuilderRespectsContainerScope()
{
_container.RegisterCollectionBuilder<TestCollectionBuilderScope>()
_composition.GetCollectionBuilder<TestCollectionBuilderScope>()
.Append<Resolved1>()
.Append<Resolved2>();
@@ -369,7 +372,7 @@ namespace Umbraco.Tests.Composing
[Test]
public void WeightedBuilderCreatesWeightedCollection()
{
var builder = _container.RegisterCollectionBuilder<TestCollectionBuilderWeighted>()
var builder = _composition.GetCollectionBuilder<TestCollectionBuilderWeighted>()
.Add<Resolved1>()
.Add<Resolved2>();
@@ -434,20 +437,12 @@ namespace Umbraco.Tests.Composing
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollectionBuilder : OrderedCollectionBuilderBase<TestCollectionBuilder, TestCollection, Resolved>
{
public TestCollectionBuilder(IContainer container)
: base(container)
{ }
protected override TestCollectionBuilder This => this;
}
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollectionBuilderTransient : OrderedCollectionBuilderBase<TestCollectionBuilderTransient, TestCollection, Resolved>
{
public TestCollectionBuilderTransient(IContainer container)
: base(container)
{ }
protected override TestCollectionBuilderTransient This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient; // transient
@@ -456,10 +451,6 @@ namespace Umbraco.Tests.Composing
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollectionBuilderScope : OrderedCollectionBuilderBase<TestCollectionBuilderScope, TestCollection, Resolved>
{
public TestCollectionBuilderScope(IContainer container)
: base(container)
{ }
protected override TestCollectionBuilderScope This => this;
protected override Lifetime CollectionLifetime => Lifetime.Scope;
@@ -468,10 +459,6 @@ namespace Umbraco.Tests.Composing
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollectionBuilderWeighted : WeightedCollectionBuilderBase<TestCollectionBuilderWeighted, TestCollection, Resolved>
{
public TestCollectionBuilderWeighted(IContainer container)
: base(container)
{ }
protected override TestCollectionBuilderWeighted This => this;
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
namespace Umbraco.Tests.Composing
@@ -33,8 +34,9 @@ namespace Umbraco.Tests.Composing
public void LazyCollectionBuilderHandlesTypes()
{
var container = CreateContainer();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<TestCollectionBuilder>()
composition.GetCollectionBuilder<TestCollectionBuilder>()
.Add<TransientObject3>()
.Add<TransientObject2>()
.Add<TransientObject3>()
@@ -56,8 +58,9 @@ namespace Umbraco.Tests.Composing
public void LazyCollectionBuilderHandlesProducers()
{
var container = CreateContainer();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<TestCollectionBuilder>()
composition.GetCollectionBuilder<TestCollectionBuilder>()
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) })
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) })
.Add(() => new[] { typeof(TransientObject1) });
@@ -78,8 +81,9 @@ namespace Umbraco.Tests.Composing
public void LazyCollectionBuilderHandlesTypesAndProducers()
{
var container = CreateContainer();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<TestCollectionBuilder>()
composition.GetCollectionBuilder<TestCollectionBuilder>()
.Add<TransientObject3>()
.Add<TransientObject2>()
.Add<TransientObject3>()
@@ -101,8 +105,9 @@ namespace Umbraco.Tests.Composing
public void LazyCollectionBuilderThrowsOnIllegalTypes()
{
var container = CreateContainer();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<TestCollectionBuilder>()
composition.GetCollectionBuilder<TestCollectionBuilder>()
.Add<TransientObject3>()
// illegal, does not implement the interface!
@@ -122,8 +127,9 @@ namespace Umbraco.Tests.Composing
public void LazyCollectionBuilderCanExcludeTypes()
{
var container = CreateContainer();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<TestCollectionBuilder>()
composition.GetCollectionBuilder<TestCollectionBuilder>()
.Add<TransientObject3>()
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2), typeof(TransientObject1) })
.Exclude<TransientObject3>();
@@ -162,10 +168,6 @@ namespace Umbraco.Tests.Composing
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollectionBuilder : LazyCollectionBuilderBase<TestCollectionBuilder, TestCollection, ITestInterface>
{
public TestCollectionBuilder(IContainer container)
: base(container)
{ }
protected override TestCollectionBuilder This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient; // transient
@@ -2,6 +2,8 @@
using System.Linq;
using System.Xml;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core._Legacy.PackageActions;
@@ -14,8 +16,9 @@ namespace Umbraco.Tests.Composing
public void PackageActionCollectionBuilderWorks()
{
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<PackageActionCollectionBuilder>()
composition.GetCollectionBuilder<PackageActionCollectionBuilder>()
.Add(() => TypeLoader.GetPackageActions());
var actions = Current.PackageActions;
@@ -52,7 +52,7 @@ namespace Umbraco.Tests.Integration
Container.Register<IServerRegistrar>(_ => new TestServerRegistrar()); // localhost-only
Container.RegisterSingleton<IServerMessenger, LocalServerMessenger>();
Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
Composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add<ContentTypeCacheRefresher>()
.Add<ContentCacheRefresher>()
.Add<MacroCacheRefresher>();
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Misc
[Test]
public void NoApplicationUrlByDefault()
{
var state = new RuntimeState(Mock.Of<ILogger>(), new Lazy<IServerRegistrar>(Mock.Of<IServerRegistrar>), new Lazy<MainDom>(Mock.Of<MainDom>), Mock.Of<IUmbracoSettingsSection>(), Mock.Of<IGlobalSettings>());
var state = new RuntimeState(Mock.Of<ILogger>(), Mock.Of<IUmbracoSettingsSection>(), Mock.Of<IGlobalSettings>(), new Lazy<MainDom>(), new Lazy<IServerRegistrar>());
Assert.IsNull(state.ApplicationUrl);
}
@@ -46,10 +46,7 @@ namespace Umbraco.Tests.Misc
var registrar = new Mock<IServerRegistrar>();
registrar.Setup(x => x.GetCurrentServerUmbracoApplicationUrl()).Returns("http://server1.com/umbraco");
var state = new RuntimeState(
Mock.Of<ILogger>(),
new Lazy<IServerRegistrar>(() => registrar.Object),
new Lazy<MainDom>(Mock.Of<MainDom>), settings, globalConfig.Object);
var state = new RuntimeState(Mock.Of<ILogger>(), settings, globalConfig.Object, new Lazy<MainDom>(), new Lazy<IServerRegistrar>(() => registrar.Object));
state.EnsureApplicationUrl();
@@ -72,7 +69,7 @@ namespace Umbraco.Tests.Misc
var state = new RuntimeState(Mock.Of<ILogger>(), new Lazy<IServerRegistrar>(Mock.Of<IServerRegistrar>), new Lazy<MainDom>(Mock.Of<MainDom>), settings, globalConfig.Object);
var state = new RuntimeState(Mock.Of<ILogger>(), settings, globalConfig.Object, new Lazy<MainDom>(), new Lazy<IServerRegistrar>(() => Mock.Of<IServerRegistrar>()));
state.EnsureApplicationUrl();
@@ -147,7 +144,5 @@ namespace Umbraco.Tests.Misc
Assert.AreEqual("httpx://whatever.com/umbraco", url);
}
}
}
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Models.Mapping
Container.Register(_ => manifestBuilder);
Func<IEnumerable<Type>> typeListProducerList = Enumerable.Empty<Type>;
Container.GetInstance<DataEditorCollectionBuilder>()
Composition.GetCollectionBuilder<DataEditorCollectionBuilder>()
.Clear()
.Add(typeListProducerList);
}
@@ -33,7 +33,7 @@ namespace Umbraco.Tests.Persistence
_sqlCeSyntaxProvider = new SqlCeSyntaxProvider();
_sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider };
_logger = Mock.Of<ILogger>();
_databaseFactory = new UmbracoDatabaseFactory(_sqlSyntaxProviders, _logger, Mock.Of<IMapperCollection>());
_databaseFactory = new UmbracoDatabaseFactory(_logger, new Lazy<IMapperCollection>(() => Mock.Of<IMapperCollection>()));
}
[TearDown]
@@ -76,7 +76,7 @@ namespace Umbraco.Tests.Persistence
}
// re-create the database factory and database context with proper connection string
_databaseFactory = new UmbracoDatabaseFactory(connString, Constants.DbProviderNames.SqlCe, _sqlSyntaxProviders, _logger, Mock.Of<IMapperCollection>());
_databaseFactory = new UmbracoDatabaseFactory(connString, Constants.DbProviderNames.SqlCe, _logger, new Lazy<IMapperCollection>(() => Mock.Of<IMapperCollection>()));
// create application context
//var appCtx = new ApplicationContext(
@@ -19,8 +19,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
{
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=x;password=umbraco";
const string providerName = Constants.DbProviderNames.SqlServer;
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null)) };
var factory = new UmbracoDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), Mock.Of<IMapperCollection>());
var factory = new UmbracoDatabaseFactory(connectionString, providerName, Mock.Of<ILogger>(), new Lazy<IMapperCollection>(() => Mock.Of<IMapperCollection>()));
using (var database = factory.CreateDatabase())
{
@@ -34,8 +33,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
{
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco";
const string providerName = Constants.DbProviderNames.SqlServer;
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null)) };
var factory = new UmbracoDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), Mock.Of<IMapperCollection>());
var factory = new UmbracoDatabaseFactory(connectionString, providerName, Mock.Of<ILogger>(), new Lazy<IMapperCollection>(() => Mock.Of<IMapperCollection>()));
using (var database = factory.CreateDatabase())
{
@@ -670,7 +670,7 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void AliasRegexTest()
{
var regex = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null)).AliasRegex;
var regex = new SqlServerSyntaxProvider().AliasRegex;
Assert.AreEqual(@"(\[\w+]\.\[\w+])\s+AS\s+(\[\w+])", regex.ToString());
const string sql = "SELECT [table].[column1] AS [alias1], [table].[column2] AS [alias2] FROM [table];";
var matches = regex.Matches(sql);
@@ -74,7 +74,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
[Test]
public void Format_SqlServer_NonClusteredIndexDefinition_AddsNonClusteredDirective()
{
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var indexDefinition = CreateIndexDefinition();
indexDefinition.IndexType = IndexTypes.NonClustered;
@@ -86,7 +86,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
[Test]
public void Format_SqlServer_NonClusteredIndexDefinition_UsingIsClusteredFalse_AddsClusteredDirective()
{
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var indexDefinition = CreateIndexDefinition();
indexDefinition.IndexType = IndexTypes.Clustered;
@@ -99,7 +99,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
public void CreateIndexBuilder_SqlServer_NonClustered_CreatesNonClusteredIndex()
{
var logger = Mock.Of<ILogger>();
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax);
var context = new MigrationContext(db, logger);
@@ -120,7 +120,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex()
{
var logger = Mock.Of<ILogger>();
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax);
var context = new MigrationContext(db, logger);
@@ -141,7 +141,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex_Multi_Columnn()
{
var logger = Mock.Of<ILogger>();
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax);
var context = new MigrationContext(db, logger);
@@ -162,7 +162,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine,
public void CreateIndexBuilder_SqlServer_Clustered_CreatesClusteredIndex()
{
var logger = Mock.Of<ILogger>();
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null));
var sqlSyntax = new SqlServerSyntaxProvider();
var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax);
var context = new MigrationContext(db, logger);
@@ -5,6 +5,7 @@ using Newtonsoft.Json;
using NUnit.Framework;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -67,8 +68,9 @@ namespace Umbraco.Tests.PropertyEditors
try
{
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>();
composition.GetCollectionBuilder<PropertyValueConverterCollectionBuilder>();
var logger = Mock.Of<ILogger>();
var scheme = Mock.Of<IMediaPathScheme>();
@@ -4,6 +4,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -172,9 +173,9 @@ namespace Umbraco.Tests.Published
{
Current.Reset();
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
Current.Container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>()
composition.GetCollectionBuilder<PropertyValueConverterCollectionBuilder>()
.Append<SimpleConverter3A>()
.Append<SimpleConverter3B>();
@@ -23,10 +23,8 @@ namespace Umbraco.Tests.PublishedContent
// fixme - what about the if (PropertyValueConvertersResolver.HasCurrent == false) ??
// can we risk double - registering and then, what happens?
var builder = Container.TryGetInstance<PropertyValueConverterCollectionBuilder>()
?? Container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>();
builder.Clear()
Composition.GetCollectionBuilder<PropertyValueConverterCollectionBuilder>()
.Clear()
.Append<DatePickerValueConverter>()
.Append<TinyMceValueConverter>()
.Append<YesNoValueConverter>();
@@ -39,7 +39,7 @@ namespace Umbraco.Tests.PublishedContent
{
base.Compose();
Container.GetInstance<UrlSegmentProviderCollectionBuilder>()
Composition.GetCollectionBuilder<UrlSegmentProviderCollectionBuilder>()
.Clear()
.Append<DefaultUrlSegmentProvider>();
}
@@ -32,7 +32,8 @@ namespace Umbraco.Tests.Routing
//create the module
var logger = Mock.Of<ILogger>();
var globalSettings = TestObjects.GetGlobalSettings();
var runtime = new RuntimeState(logger, new Lazy<IServerRegistrar>(), new Lazy<MainDom>(), Mock.Of<IUmbracoSettingsSection>(), globalSettings);
var runtime = new RuntimeState(logger, Mock.Of<IUmbracoSettingsSection>(), globalSettings,
new Lazy<MainDom>(), new Lazy<IServerRegistrar>());
_module = new UmbracoInjectedModule
(
@@ -74,9 +74,11 @@ namespace Umbraco.Tests.Runtimes
return new DebugDiagnosticsLogger();
}
public override void Compose(IContainer container)
public override void Compose(Composition composition)
{
base.Compose(container);
base.Compose(composition);
var container = composition.Container;
// the application's profiler and profiling logger are
// registered by CoreRuntime.Compose() but can be
@@ -100,7 +102,7 @@ namespace Umbraco.Tests.Runtimes
// pretend we have the proper migration
// else BootFailedException because our mock IUmbracoDatabaseFactory does not provide databases
protected override bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger)
protected override bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory)
{
return true;
}
@@ -122,7 +124,7 @@ namespace Umbraco.Tests.Runtimes
// runs with only one single component
// UmbracoCoreComponent will be force-added too
// and that's it
protected override IEnumerable<Type> GetComponentTypes()
protected override IEnumerable<Type> GetComponentTypes(TypeLoader typeLoader)
{
return new[] { typeof(TestComponent) };
}
@@ -3,6 +3,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Components;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.IO;
@@ -30,11 +31,12 @@ namespace Umbraco.Tests.Scoping
DoThing3 = null;
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
_testObjects = new TestObjects(container);
Current.Container.RegisterSingleton(factory => new FileSystems(container, factory.TryGetInstance<ILogger>()));
Current.Container.RegisterCollectionBuilder<MapperCollectionBuilder>();
composition.GetCollectionBuilder<MapperCollectionBuilder>();
SettingsForTests.Reset(); // ensure we have configuration
}
@@ -46,7 +46,7 @@ namespace Umbraco.Tests.Scoping
// so doing all this mess
Container.RegisterSingleton<IServerMessenger, ScopedXmlTests.LocalServerMessenger>();
Container.RegisterSingleton(f => Mock.Of<IServerRegistrar>());
Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
Composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add(f => f.TryGetInstance<TypeLoader>().GetCacheRefreshers());
}
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Scoping
// so doing all this mess
Container.RegisterSingleton<IServerMessenger, LocalServerMessenger>();
Container.RegisterSingleton(f => Mock.Of<IServerRegistrar>());
Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
Composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add(f => f.TryGetInstance<TypeLoader>().GetCacheRefreshers());
}
+1 -1
View File
@@ -34,7 +34,7 @@ namespace Umbraco.Tests.Scoping
// so doing all this mess
Container.RegisterSingleton<IServerMessenger, LocalServerMessenger>();
Container.RegisterSingleton(f => Mock.Of<IServerRegistrar>());
Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
Composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add(f => f.TryGetInstance<TypeLoader>().GetCacheRefreshers());
}
@@ -57,8 +57,7 @@ namespace Umbraco.Tests.Services
{
base.Compose();
// fixme - do it differently
Container.Register(factory => factory.GetInstance<ServiceContext>().TextService);
Container.RegisterSingleton(factory => Mock.Of<ILocalizedTextService>());
}
/// <summary>
@@ -37,7 +37,7 @@ namespace Umbraco.Tests.Services
// pfew - see note in ScopedNuCacheTests?
Container.RegisterSingleton<IServerMessenger, LocalServerMessenger>();
Container.RegisterSingleton(f => Mock.Of<IServerRegistrar>());
Container.RegisterCollectionBuilder<CacheRefresherCollectionBuilder>()
Composition.GetCollectionBuilder<CacheRefresherCollectionBuilder>()
.Add(f => f.TryGetInstance<TypeLoader>().GetCacheRefreshers());
}
@@ -770,4 +770,4 @@ namespace Umbraco.Tests.Services
"{'properties':{'value11':[{'culture':'','seg':'','val':'v11'}],'value12':[{'culture':'','seg':'','val':'v12'}],'value31':[{'culture':'','seg':'','val':'v31'}],'value32':[{'culture':'','seg':'','val':'v32'}]},'cultureData':");
}
}
}
}
@@ -49,7 +49,7 @@ namespace Umbraco.Tests.Services.Importing
// pollute everything, they are ignored by the type finder and explicitely
// added to the editors collection
Container.GetInstance<DataEditorCollectionBuilder>()
Composition.GetCollectionBuilder<DataEditorCollectionBuilder>()
.Add<Editor1>()
.Add<Editor2>();
}
@@ -3,6 +3,7 @@ using NPoco;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -33,6 +34,7 @@ namespace Umbraco.Tests.TestHelpers
var sqlSyntax = new SqlCeSyntaxProvider();
var container = Current.Container = ContainerFactory.Create();
var composition = new Composition(container, RuntimeLevel.Run);
container.RegisterSingleton<ILogger>(factory => Mock.Of<ILogger>());
container.RegisterSingleton<IProfiler>(factory => Mock.Of<IProfiler>());
@@ -44,7 +46,7 @@ namespace Umbraco.Tests.TestHelpers
false);
container.RegisterInstance(pluginManager);
container.RegisterCollectionBuilder<MapperCollectionBuilder>()
composition.GetCollectionBuilder<MapperCollectionBuilder>()
.Add(() => Current.TypeLoader.GetAssignedMapperTypes());
Mappers = container.GetInstance<IMapperCollection>();
+2 -18
View File
@@ -37,22 +37,6 @@ namespace Umbraco.Tests.TestHelpers
_container = container;
}
/// <summary>
/// Gets the default ISqlSyntaxProvider objects.
/// </summary>
/// <param name="logger">A logger.</param>
/// <param name="lazyScopeProvider">A (lazy) scope provider.</param>
/// <returns>The default ISqlSyntaxProvider objects.</returns>
public IEnumerable<ISqlSyntaxProvider> GetDefaultSqlSyntaxProviders(ILogger logger, Lazy<IScopeProvider> lazyScopeProvider = null)
{
return new ISqlSyntaxProvider[]
{
new MySqlSyntaxProvider(logger),
new SqlCeSyntaxProvider(),
new SqlServerSyntaxProvider(lazyScopeProvider ?? new Lazy<IScopeProvider>(() => null))
};
}
/// <summary>
/// Gets an UmbracoDatabase.
/// </summary>
@@ -77,7 +61,7 @@ namespace Umbraco.Tests.TestHelpers
/// that can begin a transaction.</remarks>
public UmbracoDatabase GetUmbracoSqlServerDatabase(ILogger logger)
{
var syntax = new SqlServerSyntaxProvider(new Lazy<IScopeProvider>(() => null)); // do NOT try to get the server's version!
var syntax = new SqlServerSyntaxProvider(); // do NOT try to get the server's version!
var connection = GetDbConnection();
var sqlContext = new SqlContext(syntax, DatabaseType.SqlServer2008, Mock.Of<IPocoDataFactory>());
return new UmbracoDatabase(connection, sqlContext, logger);
@@ -241,7 +225,7 @@ namespace Umbraco.Tests.TestHelpers
//mappersBuilder.AddCore();
//var mappers = mappersBuilder.CreateCollection();
var mappers = Current.Container.GetInstance<IMapperCollection>();
databaseFactory = new UmbracoDatabaseFactory(Constants.System.UmbracoConnectionName, GetDefaultSqlSyntaxProviders(logger), logger, mappers);
databaseFactory = new UmbracoDatabaseFactory(Constants.System.UmbracoConnectionName, logger, new Lazy<IMapperCollection>(() => mappers));
}
fileSystems = fileSystems ?? new FileSystems(Current.Container, logger);
@@ -76,7 +76,7 @@ namespace Umbraco.Tests.TestHelpers
Container.Register(factory => PublishedSnapshotService);
Container.Register(factory => DefaultCultureAccessor);
Container.GetInstance<DataEditorCollectionBuilder>()
Composition.GetCollectionBuilder<DataEditorCollectionBuilder>()
.Clear()
.Add(f => f.GetInstance<TypeLoader>().GetDataEditors());
@@ -85,10 +85,9 @@ namespace Umbraco.Tests.TestHelpers
if (Options.Database == UmbracoTestOptions.Database.None)
return TestObjects.GetDatabaseFactoryMock();
var sqlSyntaxProviders = new[] { new SqlCeSyntaxProvider() };
var logger = f.GetInstance<ILogger>();
var mappers = f.GetInstance<IMapperCollection>();
var factory = new UmbracoDatabaseFactory(GetDbConnectionString(), GetDbProviderName(), sqlSyntaxProviders, logger, mappers);
var factory = new UmbracoDatabaseFactory(GetDbConnectionString(), GetDbProviderName(), logger, new Lazy<IMapperCollection>(() => mappers));
factory.ResetForTests();
return factory;
});
+13 -14
View File
@@ -76,6 +76,8 @@ 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 IContainer Container { get; private set; }
protected UmbracoTestAttribute Options { get; private set; }
@@ -116,6 +118,7 @@ namespace Umbraco.Tests.Testing
Reset();
Container = Current.Container = ContainerFactory.Create();
Composition = new Composition(Container, RuntimeLevel.Run);
TestObjects = new TestObjects(Container);
@@ -189,7 +192,7 @@ namespace Umbraco.Tests.Testing
// web
Container.Register(_ => Umbraco.Web.Composing.Current.UmbracoContextAccessor);
Container.RegisterSingleton<PublishedRouter>();
Container.RegisterCollectionBuilder<ContentFinderCollectionBuilder>();
Composition.GetCollectionBuilder<ContentFinderCollectionBuilder>();
Container.Register<IContentLastChanceFinder, TestLastChanceFinder>();
Container.Register<IVariationContextAccessor, TestVariationContextAccessor>();
}
@@ -202,14 +205,14 @@ namespace Umbraco.Tests.Testing
Container.RegisterSingleton(f => runtimeStateMock.Object);
// ah...
Container.RegisterCollectionBuilder<ActionCollectionBuilder>();
Container.RegisterCollectionBuilder<PropertyValueConverterCollectionBuilder>();
Composition.GetCollectionBuilder<ActionCollectionBuilder>();
Composition.GetCollectionBuilder<PropertyValueConverterCollectionBuilder>();
Container.RegisterSingleton<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
Container.RegisterSingleton<IMediaPathScheme, OriginalMediaPathScheme>();
// register empty content apps collection
Container.RegisterCollectionBuilder<ContentAppDefinitionCollectionBuilder>();
Composition.GetCollectionBuilder<ContentAppDefinitionCollectionBuilder>();
}
protected virtual void ComposeCacheHelper()
@@ -307,20 +310,17 @@ namespace Umbraco.Tests.Testing
Container.RegisterSingleton<IPublishedModelFactory, NoopPublishedModelFactory>();
// register application stuff (database factory & context, services...)
Container.RegisterCollectionBuilder<MapperCollectionBuilder>()
.AddCore();
Composition.GetCollectionBuilder<MapperCollectionBuilder>()
.AddCoreMappers();
Container.RegisterSingleton<IEventMessagesFactory>(_ => new TransientEventMessagesFactory());
var sqlSyntaxProviders = TestObjects.GetDefaultSqlSyntaxProviders(Logger);
Container.RegisterSingleton<ISqlSyntaxProvider>(_ => sqlSyntaxProviders.OfType<SqlCeSyntaxProvider>().First());
Container.RegisterSingleton<IUmbracoDatabaseFactory>(f => new UmbracoDatabaseFactory(
Constants.System.UmbracoConnectionName,
sqlSyntaxProviders,
Logger,
Mock.Of<IMapperCollection>()));
new Lazy<IMapperCollection>(() => Mock.Of<IMapperCollection>())));
Container.RegisterSingleton(f => f.TryGetInstance<IUmbracoDatabaseFactory>().SqlContext);
Container.RegisterCollectionBuilder<UrlSegmentProviderCollectionBuilder>(); // empty
Composition.GetCollectionBuilder<UrlSegmentProviderCollectionBuilder>(); // empty
Container.RegisterSingleton(factory
=> TestObjects.GetScopeProvider(factory.TryGetInstance<ILogger>(), factory.TryGetInstance<FileSystems>(), factory.TryGetInstance<IUmbracoDatabaseFactory>()));
@@ -333,12 +333,11 @@ namespace Umbraco.Tests.Testing
Container.RegisterSingleton<ISectionService, SectionService>();
// somehow property editor ends up wanting this
Container.RegisterCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
Composition.GetCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
Container.RegisterSingleton<ManifestParser>();
// note - don't register collections, use builders
Container.RegisterCollectionBuilder<DataEditorCollectionBuilder>();
var temp = Container.GetInstance<DataEditorCollectionBuilder>();
Composition.GetCollectionBuilder<DataEditorCollectionBuilder>();
Container.RegisterSingleton<PropertyEditorCollection>();
Container.RegisterSingleton<ParameterEditorCollection>();
}
@@ -7,10 +7,6 @@ namespace Umbraco.Web.Actions
{
internal class ActionCollectionBuilder : LazyCollectionBuilderBase<ActionCollectionBuilder, ActionCollection, IAction>
{
public ActionCollectionBuilder(IContainer container)
: base(container)
{ }
protected override ActionCollectionBuilder This => this;
protected override IEnumerable<IAction> CreateItems()
@@ -9,10 +9,6 @@ namespace Umbraco.Web.ContentApps
{
public class ContentAppDefinitionCollectionBuilder : OrderedCollectionBuilderBase<ContentAppDefinitionCollectionBuilder, ContentAppDefinitionCollection, IContentAppDefinition>
{
public ContentAppDefinitionCollectionBuilder(IContainer container)
: base(container)
{ }
protected override ContentAppDefinitionCollectionBuilder This => this;
// need to inject dependencies in the collection, so override creation
@@ -4,10 +4,6 @@ namespace Umbraco.Web.Editors
{
internal class EditorValidatorCollectionBuilder : LazyCollectionBuilderBase<EditorValidatorCollectionBuilder, EditorValidatorCollection, IEditorValidator>
{
public EditorValidatorCollectionBuilder(IContainer container)
: base(container)
{ }
protected override EditorValidatorCollectionBuilder This => this;
}
}
@@ -5,10 +5,6 @@ namespace Umbraco.Web.HealthCheck
{
internal class HealthCheckNotificationMethodCollectionBuilder : LazyCollectionBuilderBase<HealthCheckNotificationMethodCollectionBuilder, HealthCheckNotificationMethodCollection, IHealthCheckNotificationMethod>
{
public HealthCheckNotificationMethodCollectionBuilder(IContainer container)
: base(container)
{ }
protected override HealthCheckNotificationMethodCollectionBuilder This => this;
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Web.HealthCheck
{
public class HealthCheckCollectionBuilder : LazyCollectionBuilderBase<HealthCheckCollectionBuilder, HealthCheckCollection, HealthCheck>
{
public HealthCheckCollectionBuilder(IContainer container)
: base(container)
{ }
protected override HealthCheckCollectionBuilder This => this;
// note: in v7 they were per-request, not sure why?
@@ -4,10 +4,6 @@ namespace Umbraco.Web.Mvc
{
public class FilteredControllerFactoryCollectionBuilder : OrderedCollectionBuilderBase<FilteredControllerFactoryCollectionBuilder, FilteredControllerFactoryCollection, IFilteredControllerFactory>
{
public FilteredControllerFactoryCollectionBuilder(IContainer container)
: base(container)
{ }
protected override FilteredControllerFactoryCollectionBuilder This => this;
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Web.Routing
{
public class ContentFinderCollectionBuilder : OrderedCollectionBuilderBase<ContentFinderCollectionBuilder, ContentFinderCollection, IContentFinder>
{
public ContentFinderCollectionBuilder(IContainer container)
: base(container)
{ }
protected override ContentFinderCollectionBuilder This => this;
}
}
@@ -4,10 +4,6 @@ namespace Umbraco.Web.Routing
{
public class UrlProviderCollectionBuilder : OrderedCollectionBuilderBase<UrlProviderCollectionBuilder, UrlProviderCollection, IUrlProvider>
{
public UrlProviderCollectionBuilder(IContainer container)
: base(container)
{ }
protected override UrlProviderCollectionBuilder This => this;
}
}
+11 -27
View File
@@ -1,5 +1,6 @@
using System.Web;
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
@@ -51,21 +52,23 @@ namespace Umbraco.Web.Runtime
}
/// <inheritdoc/>
public override void Compose(IContainer container)
public override void Compose(Composition composition)
{
base.Compose(composition);
var container = composition.Container;
// some components may want to initialize with the UmbracoApplicationBase
// well, they should not - we should not do this
// TODO remove this eventually.
container.RegisterInstance(_umbracoApplication);
base.Compose(container);
}
container.Register<UmbracoInjectedModule>();
#region Getters
// replace CoreRuntime's IProfiler registration
container.RegisterSingleton(_ => _webProfiler);
protected override IProfiler GetProfiler() => new WebProfiler();
// replace CoreRuntime's CacheHelper registration
container.RegisterSingleton(_ => new CacheHelper(
protected override CacheHelper GetAppCaches() => new CacheHelper(
// we need to have the dep clone runtime cache provider to ensure
// all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new HttpRuntimeCacheProvider(HttpRuntime.Cache)),
@@ -75,26 +78,7 @@ namespace Umbraco.Web.Runtime
new IsolatedRuntimeCache(type =>
// we need to have the dep clone runtime cache provider to ensure
// all entities are cached properly (cloned in and cloned out)
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))));
container.RegisterSingleton<IHttpContextAccessor, AspNetHttpContextAccessor>(); // required for hybrid accessors
}
#region Getters
//protected override IProfiler GetProfiler() => new WebProfiler();
//protected override CacheHelper GetApplicationCache() => new CacheHelper(
// // we need to have the dep clone runtime cache provider to ensure
// // all entities are cached properly (cloned in and cloned out)
// new DeepCloneRuntimeCacheProvider(new HttpRuntimeCacheProvider(HttpRuntime.Cache)),
// new StaticCacheProvider(),
// // we need request based cache when running in web-based context
// new HttpRequestCacheProvider(),
// new IsolatedRuntimeCache(type =>
// // we need to have the dep clone runtime cache provider to ensure
// // all entities are cached properly (cloned in and cloned out)
// new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())));
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())));
#endregion
}
+52 -46
View File
@@ -64,109 +64,115 @@ namespace Umbraco.Web.Runtime
{
base.Compose(composition);
composition.Container.ComposeWebMappingProfiles();
var container = composition.Container;
container.Register<UmbracoInjectedModule>();
container.RegisterSingleton<IHttpContextAccessor, AspNetHttpContextAccessor>(); // required for hybrid accessors
container.ComposeWebMappingProfiles();
//register the install components
//NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts
//it still needs to use the install controller so we can't do that
composition.Container.ComposeInstaller();
container.ComposeInstaller();
// register membership stuff
composition.Container.Register(factory => Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider());
composition.Container.Register(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetInstance<IMemberService>()));
composition.Container.Register<MembershipHelper>();
container.Register(factory => Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider());
container.Register(factory => Roles.Enabled ? Roles.Provider : new MembersRoleProvider(factory.GetInstance<IMemberService>()));
container.Register<MembershipHelper>();
// register accessors for cultures
composition.Container.RegisterSingleton<IDefaultCultureAccessor, DefaultCultureAccessor>();
composition.Container.RegisterSingleton<IVariationContextAccessor, HttpContextVariationContextAccessor>();
container.RegisterSingleton<IDefaultCultureAccessor, DefaultCultureAccessor>();
container.RegisterSingleton<IVariationContextAccessor, HttpContextVariationContextAccessor>();
var typeLoader = composition.Container.GetInstance<TypeLoader>();
var logger = composition.Container.GetInstance<ILogger>();
var proflog = composition.Container.GetInstance<ProfilingLogger>();
var typeLoader = container.GetInstance<TypeLoader>();
var logger = container.GetInstance<ILogger>();
var proflog = container.GetInstance<ProfilingLogger>();
// 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.Container.RegisterSingleton<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
container.RegisterSingleton<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
// register a per-request HttpContextBase object
// is per-request so only one wrapper is created per request
composition.Container.Register<HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance<IHttpContextAccessor>().HttpContext), Lifetime.Request);
container.Register<HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance<IHttpContextAccessor>().HttpContext), Lifetime.Request);
// register the published snapshot accessor - the "current" published snapshot is in the umbraco context
composition.Container.RegisterSingleton<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
container.RegisterSingleton<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
// we should stop injecting UmbracoContext and always inject IUmbracoContextAccessor, however at the moment
// there are tons of places (controllers...) which require UmbracoContext in their ctor - so let's register
// a way to inject the UmbracoContext - and register it per-request to be more efficient
//TODO: stop doing this
composition.Container.Register(factory => factory.GetInstance<IUmbracoContextAccessor>().UmbracoContext, Lifetime.Request);
container.Register(factory => factory.GetInstance<IUmbracoContextAccessor>().UmbracoContext, Lifetime.Request);
// register the umbraco helper
composition.Container.RegisterSingleton<UmbracoHelper>();
container.RegisterSingleton<UmbracoHelper>();
// register distributed cache
composition.Container.RegisterSingleton(f => new DistributedCache());
container.RegisterSingleton(f => new DistributedCache());
// replace some services
composition.Container.RegisterSingleton<IEventMessagesFactory, DefaultEventMessagesFactory>();
composition.Container.RegisterSingleton<IEventMessagesAccessor, HybridEventMessagesAccessor>();
composition.Container.RegisterSingleton<IApplicationTreeService, ApplicationTreeService>();
composition.Container.RegisterSingleton<ISectionService, SectionService>();
container.RegisterSingleton<IEventMessagesFactory, DefaultEventMessagesFactory>();
container.RegisterSingleton<IEventMessagesAccessor, HybridEventMessagesAccessor>();
container.RegisterSingleton<IApplicationTreeService, ApplicationTreeService>();
container.RegisterSingleton<ISectionService, SectionService>();
composition.Container.RegisterSingleton<IExamineManager>(factory => ExamineManager.Instance);
container.RegisterSingleton<IExamineManager>(factory => ExamineManager.Instance);
// configure the container for web
composition.Container.ConfigureForWeb();
composition.Container.ComposeMvcControllers(typeLoader, GetType().Assembly);
composition.Container.ComposeApiControllers(typeLoader, GetType().Assembly);
container.ConfigureForWeb();
container.ComposeMvcControllers(typeLoader, GetType().Assembly);
container.ComposeApiControllers(typeLoader, GetType().Assembly);
composition.Container.RegisterCollectionBuilder<SearchableTreeCollectionBuilder>()
composition.GetCollectionBuilder<SearchableTreeCollectionBuilder>()
.Add(() => typeLoader.GetTypes<ISearchableTree>()); // fixme which searchable trees?!
composition.Container.RegisterCollectionBuilder<EditorValidatorCollectionBuilder>()
composition.GetCollectionBuilder<EditorValidatorCollectionBuilder>()
.Add(() => typeLoader.GetTypes<IEditorValidator>());
composition.Container.RegisterCollectionBuilder<TourFilterCollectionBuilder>();
composition.GetCollectionBuilder<TourFilterCollectionBuilder>();
composition.Container.RegisterSingleton<UmbracoFeatures>();
container.RegisterSingleton<UmbracoFeatures>();
// set the default RenderMvcController
Current.DefaultRenderMvcControllerType = typeof(RenderMvcController); // fixme WRONG!
composition.Container.RegisterCollectionBuilder<ActionCollectionBuilder>()
composition.GetCollectionBuilder<ActionCollectionBuilder>()
.Add(() => typeLoader.GetTypes<IAction>());
var surfaceControllerTypes = new SurfaceControllerTypeCollection(typeLoader.GetSurfaceControllers());
composition.Container.RegisterInstance(surfaceControllerTypes);
container.RegisterInstance(surfaceControllerTypes);
var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(typeLoader.GetUmbracoApiControllers());
composition.Container.RegisterInstance(umbracoApiControllerTypes);
container.RegisterInstance(umbracoApiControllerTypes);
// 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.Container.GetInstance<PropertyValueConverterCollectionBuilder>()
container.GetInstance<PropertyValueConverterCollectionBuilder>()
.Remove<TinyMceValueConverter>()
.Remove<TextStringValueConverter>()
.Remove<MarkdownEditorValueConverter>();
// add all known factories, devs can then modify this list on application
// startup either by binding to events or in their own global.asax
composition.Container.RegisterCollectionBuilder<FilteredControllerFactoryCollectionBuilder>()
composition.GetCollectionBuilder<FilteredControllerFactoryCollectionBuilder>()
.Append<RenderControllerFactory>();
composition.Container.RegisterCollectionBuilder<UrlProviderCollectionBuilder>()
composition.GetCollectionBuilder<UrlProviderCollectionBuilder>()
.Append<AliasUrlProvider>()
.Append<DefaultUrlProvider>()
.Append<CustomRouteUrlProvider>();
composition.Container.RegisterSingleton<IContentLastChanceFinder, ContentFinderByLegacy404>();
container.RegisterSingleton<IContentLastChanceFinder, ContentFinderByLegacy404>();
composition.Container.RegisterCollectionBuilder<ContentFinderCollectionBuilder>()
composition.GetCollectionBuilder<ContentFinderCollectionBuilder>()
// all built-in finders in the correct order,
// devs can then modify this list on application startup
.Append<ContentFinderByPageIdQuery>()
@@ -176,32 +182,32 @@ namespace Umbraco.Web.Runtime
.Append<ContentFinderByUrlAlias>()
.Append<ContentFinderByRedirectUrl>();
composition.Container.RegisterSingleton<ISiteDomainHelper, SiteDomainHelper>();
container.RegisterSingleton<ISiteDomainHelper, SiteDomainHelper>();
composition.Container.RegisterSingleton<ICultureDictionaryFactory, DefaultCultureDictionaryFactory>();
container.RegisterSingleton<ICultureDictionaryFactory, DefaultCultureDictionaryFactory>();
// register *all* checks, except those marked [HideFromTypeFinder] of course
composition.Container.RegisterCollectionBuilder<HealthCheckCollectionBuilder>()
composition.GetCollectionBuilder<HealthCheckCollectionBuilder>()
.Add(() => typeLoader.GetTypes<HealthCheck.HealthCheck>());
composition.Container.RegisterCollectionBuilder<HealthCheckNotificationMethodCollectionBuilder>()
composition.GetCollectionBuilder<HealthCheckNotificationMethodCollectionBuilder>()
.Add(() => typeLoader.GetTypes<HealthCheck.NotificationMethods.IHealthCheckNotificationMethod>());
// auto-register views
composition.Container.RegisterAuto(typeof(UmbracoViewPage<>));
container.RegisterAuto(typeof(UmbracoViewPage<>));
// register published router
composition.Container.RegisterSingleton<PublishedRouter>();
composition.Container.Register(_ => UmbracoConfig.For.UmbracoSettings().WebRouting);
container.RegisterSingleton<PublishedRouter>();
container.Register(_ => UmbracoConfig.For.UmbracoSettings().WebRouting);
// register preview SignalR hub
composition.Container.RegisterSingleton(_ => GlobalHost.ConnectionManager.GetHubContext<PreviewHub>());
container.RegisterSingleton(_ => GlobalHost.ConnectionManager.GetHubContext<PreviewHub>());
// register properties fallback
composition.Container.RegisterSingleton<IPublishedValueFallback, PublishedValueFallback>();
container.RegisterSingleton<IPublishedValueFallback, PublishedValueFallback>();
// register known content apps
composition.Container.RegisterCollectionBuilder<ContentAppDefinitionCollectionBuilder>()
composition.GetCollectionBuilder<ContentAppDefinitionCollectionBuilder>()
.Append<ListViewContentAppDefinition>()
.Append<ContentEditorContentAppDefinition>()
.Append<ContentInfoContentAppDefinition>();
@@ -1,24 +1,10 @@
using Umbraco.Core.Composing;
using Umbraco.Core.Services;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Search
{
internal class SearchableTreeCollectionBuilder : LazyCollectionBuilderBase<SearchableTreeCollectionBuilder, SearchableTreeCollection, ISearchableTree>
{
private readonly IApplicationTreeService _treeService;
public SearchableTreeCollectionBuilder(IContainer container, IApplicationTreeService treeService)
: base(container)
{
_treeService = treeService;
}
protected override SearchableTreeCollectionBuilder This => this;
public override SearchableTreeCollection CreateCollection()
{
return new SearchableTreeCollection(CreateItems(), _treeService);
}
}
}
@@ -14,13 +14,6 @@ namespace Umbraco.Web.Tour
{
private readonly HashSet<BackOfficeTourFilter> _instances = new HashSet<BackOfficeTourFilter>();
/// <summary>
/// Initializes a new instance of the <see cref="TourFilterCollectionBuilder"/> class.
/// </summary>
public TourFilterCollectionBuilder(IContainer container)
: base(container)
{ }
/// <inheritdoc />
protected override IEnumerable<BackOfficeTourFilter> CreateItems(/*params object[] args*/)
{