Add composers via extension on UmbracoBuilder

reduce scope of CoreRuntimeBootstrapper
This commit is contained in:
Paul Johnson
2020-11-19 16:20:39 +00:00
parent 48b61ec4c4
commit 3672a9f2f2
16 changed files with 179 additions and 247 deletions

View File

@@ -1,5 +1,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Builder
@@ -9,6 +10,7 @@ namespace Umbraco.Core.Builder
IServiceCollection Services { get; }
IConfiguration Config { get; }
TypeLoader TypeLoader { get; set; } // TODO: Remove setter, see note on concrete
ILoggerFactory BuilderLoggerFactory { get; }
TBuilder WithCollectionBuilder<TBuilder>() where TBuilder : ICollectionBuilder, new();
void Build();
}

View File

@@ -2,6 +2,8 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Umbraco.Core.Builder;
using Umbraco.Core.Composing;
@@ -12,9 +14,14 @@ namespace Umbraco.Web.Common.Builder
private readonly Dictionary<Type, ICollectionBuilder> _builders = new Dictionary<Type, ICollectionBuilder>();
public UmbracoBuilder(IServiceCollection services, IConfiguration config)
: this(services, config, NullLoggerFactory.Instance)
{ }
public UmbracoBuilder(IServiceCollection services, IConfiguration config, ILoggerFactory loggerFactory)
{
Services = services;
Config = config;
BuilderLoggerFactory = loggerFactory;
}
public IServiceCollection Services { get; }
@@ -27,6 +34,7 @@ namespace Umbraco.Web.Common.Builder
/// &amp; use of IOptionsMoniker&lt;HostingSettings&gt; for AspNetCoreHostingEnvironment
/// </remarks>
public TypeLoader TypeLoader { get; set; }
public ILoggerFactory BuilderLoggerFactory { get; }
/// <summary>
/// Gets a collection builder (and registers the collection).
@@ -46,6 +54,8 @@ namespace Umbraco.Web.Common.Builder
return builder;
}
public void Build()
{
foreach (var builder in _builders.Values)

View File

@@ -19,7 +19,6 @@ namespace Umbraco.Core.Composing
{
private readonly IUmbracoBuilder _builder;
private readonly ILogger<Composers> _logger;
private readonly IProfilingLogger _profileLogger;
private readonly IEnumerable<Type> _composerTypes;
private readonly IEnumerable<Attribute> _enableDisableAttributes;
@@ -40,13 +39,12 @@ namespace Umbraco.Core.Composing
/// enableDisableAttributes
/// or
/// logger</exception>
public Composers(IUmbracoBuilder builder, IEnumerable<Type> composerTypes, IEnumerable<Attribute> enableDisableAttributes, ILogger<Composers> logger, IProfilingLogger profileLogger)
public Composers(IUmbracoBuilder builder, IEnumerable<Type> composerTypes, IEnumerable<Attribute> enableDisableAttributes, ILogger<Composers> logger)
{
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
_composerTypes = composerTypes ?? throw new ArgumentNullException(nameof(composerTypes));
_enableDisableAttributes = enableDisableAttributes ?? throw new ArgumentNullException(nameof(enableDisableAttributes));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_profileLogger = profileLogger;
}
private class EnableInfo
@@ -65,23 +63,15 @@ namespace Umbraco.Core.Composing
IEnumerable<Type> orderedComposerTypes;
using (_profileLogger.DebugDuration<Composers>("Preparing composer types.", "Prepared composer types."))
{
orderedComposerTypes = PrepareComposerTypes();
}
orderedComposerTypes = PrepareComposerTypes();
var composers = InstantiateComposers(orderedComposerTypes);
using (_profileLogger.DebugDuration<Composers>($"Composing composers. (log when >{LogThresholdMilliseconds}ms)", "Composed composers."))
foreach (var composer in composers)
{
foreach (var composer in composers)
{
var componentType = composer.GetType();
using (_profileLogger.DebugDuration<Composers>($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
composer.Compose(_builder);
}
}
var componentType = composer.GetType();
composer.Compose(_builder);
}
}
@@ -360,13 +350,10 @@ namespace Umbraco.Core.Composing
var ctor = type.GetConstructor(Array.Empty<Type>());
if (ctor == null)
throw new InvalidOperationException($"Composer {type.FullName} does not have a parameter-less constructor.");
return (IComposer) ctor.Invoke(Array.Empty<object>());
return (IComposer)ctor.Invoke(Array.Empty<object>());
}
using (_profileLogger.DebugDuration<Composers>("Instantiating composers.", "Instantiated composers."))
{
return types.Select(InstantiateComposer).ToArray();
}
return types.Select(InstantiateComposer).ToArray();
}
}
}

View File

@@ -22,18 +22,16 @@ namespace Umbraco.Core.Logging.Serilog
/// It is highly recommended that you keep/use this default in your own logging config customizations
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
/// <param name="hostingEnvironment"></param>
/// <param name="loggingConfiguration"></param>
public static LoggerConfiguration MinimalConfiguration(
this LoggerConfiguration logConfig,
IHostingEnvironment hostingEnvironment,
ILoggingConfiguration loggingConfiguration)
{
global::Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", hostingEnvironment.MapPathContentRoot("/").TrimEnd("\\"), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("BASEDIR", loggingConfiguration.LogDirectory.TrimEnd("\\"), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("UMBLOGDIR", loggingConfiguration.LogDirectory, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("MACHINENAME", Environment.MachineName, EnvironmentVariableTarget.Process);
@@ -42,7 +40,7 @@ namespace Umbraco.Core.Logging.Serilog
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty(AppDomainId, AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", hostingEnvironment.ApplicationId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.WithProperty("AppDomainAppId", AppDomain.CurrentDomain.Id.ToString().ReplaceNonAlphanumericChars(string.Empty))
.Enrich.WithProperty("MachineName", Environment.MachineName)
.Enrich.With<Log4NetLevelMapperEnricher>()
.Enrich.FromLogContext(); // allows us to dynamically enrich

View File

@@ -39,12 +39,11 @@ namespace Umbraco.Core.Logging.Serilog
/// </summary>
/// <remarks>Used by UmbracoApplicationBase to get its logger.</remarks>
public static SerilogLogger CreateWithDefaultConfiguration(
IHostingEnvironment hostingEnvironment,
ILoggingConfiguration loggingConfiguration,
IConfiguration configuration)
{
var loggerConfig = new LoggerConfiguration()
.MinimalConfiguration(hostingEnvironment, loggingConfiguration)
.MinimalConfiguration(loggingConfiguration)
.ReadFrom.Configuration(configuration);
return new SerilogLogger(loggerConfig);

View File

@@ -33,13 +33,12 @@ namespace Umbraco.Core.Runtime
private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker;
private readonly GlobalSettings _globalSettings;
private readonly ConnectionStrings _connectionStrings;
public CoreRuntimeBootstrapper(
GlobalSettings globalSettings,
ConnectionStrings connectionStrings,
IUmbracoVersion umbracoVersion,
IIOHelper ioHelper,
ILoggerFactory loggerFactory,
IProfiler profiler,
IUmbracoBootPermissionChecker umbracoBootPermissionChecker,
IHostingEnvironment hostingEnvironment,
@@ -60,20 +59,11 @@ namespace Umbraco.Core.Runtime
BackOfficeInfo = backOfficeInfo;
DbProviderFactoryCreator = dbProviderFactoryCreator;
RuntimeLoggerFactory = loggerFactory;
_umbracoBootPermissionChecker = umbracoBootPermissionChecker;
Logger = loggerFactory.CreateLogger<CoreRuntimeBootstrapper>();
MainDom = mainDom;
TypeFinder = typeFinder;
}
/// <summary>
/// Gets the logger.
/// </summary>
private ILogger<CoreRuntimeBootstrapper> Logger { get; }
public ILoggerFactory RuntimeLoggerFactory { get; }
protected IBackOfficeInfo BackOfficeInfo { get; }
@@ -84,11 +74,6 @@ namespace Umbraco.Core.Runtime
/// </summary>
protected IProfiler Profiler { get; }
/// <summary>
/// Gets the profiling logger.
/// </summary>
public IProfilingLogger ProfilingLogger { get; private set; }
/// <summary>
/// Gets the <see cref="ITypeFinder"/>
/// </summary>
@@ -127,115 +112,90 @@ namespace Umbraco.Core.Runtime
// objects.
var umbracoVersion = new UmbracoVersion();
var profilingLogger = ProfilingLogger = new ProfilingLogger(Logger, Profiler);
var logger = builder.BuilderLoggerFactory.CreateLogger<CoreRuntimeBootstrapper>();
var profilingLogger = new ProfilingLogger(logger, Profiler);
using (var timer = profilingLogger.TraceDuration<CoreRuntimeBootstrapper>(
$"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.",
"Booted.",
"Boot failed."))
{
Logger.LogInformation("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
logger.LogInformation("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
HostingEnvironment?.SiteName,
HostingEnvironment?.ApplicationId,
HostingEnvironment?.ApplicationPhysicalPath,
NetworkHelper.MachineName);
Logger.LogDebug("Runtime: {Runtime}", GetType().FullName);
logger.LogDebug("Runtime: {Runtime}", GetType().FullName);
AppDomain.CurrentDomain.SetData("DataDirectory", HostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data));
// application environment
ConfigureUnhandledException();
Configure(builder, timer);
}
}
/// <summary>
/// Configure the runtime within a timer.
/// </summary>
private void Configure(IUmbracoBuilder builder, DisposableTimer timer)
{
if (builder is null) throw new ArgumentNullException(nameof(builder));
if (timer is null) throw new ArgumentNullException(nameof(timer));
try
{
// run handlers
OnRuntimeBoot();
// TODO: Don't do this, UmbracoBuilder ctor should handle it...
builder.TypeLoader = new TypeLoader(TypeFinder, AppCaches.RuntimeCache,
new DirectoryInfo(HostingEnvironment.LocalTempPath),
RuntimeLoggerFactory.CreateLogger<TypeLoader>(), ProfilingLogger);
builder.Services.AddUnique<ILogger>(Logger);
builder.Services.AddUnique<ILoggerFactory>(RuntimeLoggerFactory);
builder.Services.AddUnique<IUmbracoBootPermissionChecker>(_umbracoBootPermissionChecker);
builder.Services.AddUnique<IProfiler>(Profiler);
builder.Services.AddUnique<IProfilingLogger>(ProfilingLogger);
builder.Services.AddUnique<IMainDom>(MainDom);
builder.Services.AddUnique<AppCaches>(AppCaches);
builder.Services.AddUnique<IRequestCache>(AppCaches.RequestCache);
builder.Services.AddUnique<TypeLoader>(builder.TypeLoader);
builder.Services.AddUnique<ITypeFinder>(TypeFinder);
builder.Services.AddUnique<IIOHelper>(IOHelper);
builder.Services.AddUnique<IUmbracoVersion>(UmbracoVersion);
builder.Services.AddUnique<IDbProviderFactoryCreator>(DbProviderFactoryCreator);
builder.Services.AddUnique<IHostingEnvironment>(HostingEnvironment);
builder.Services.AddUnique<IBackOfficeInfo>(BackOfficeInfo);
builder.Services.AddUnique<IRuntime, CoreRuntime>();
// NOTE: This instance of IUmbracoDatabaseFactory is only used to determine runtime state.
var bootstrapDatabaseFactory = CreateBootstrapDatabaseFactory();
// after bootstrapping we let the container wire up for us.
builder.Services.AddUnique<IUmbracoDatabaseFactory, UmbracoDatabaseFactory>();
builder.Services.AddUnique<ISqlContext>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().SqlContext);
builder.Services.AddUnique<IBulkSqlInsertProvider>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().BulkSqlInsertProvider);
// re-create the state object with the essential services
_state = new RuntimeState(_globalSettings, UmbracoVersion, bootstrapDatabaseFactory, RuntimeLoggerFactory.CreateLogger<RuntimeState>());
builder.Services.AddUnique<IRuntimeState>(_state);
// run handlers
OnRuntimeEssentials(builder, AppCaches, builder.TypeLoader, bootstrapDatabaseFactory);
ConfigureUnhandledException(logger);
try
{
// run handlers
OnRuntimeBoot(profilingLogger);
// TODO: Don't do this, UmbracoBuilder ctor should handle it...
builder.TypeLoader = new TypeLoader(TypeFinder, AppCaches.RuntimeCache,
new DirectoryInfo(HostingEnvironment.LocalTempPath),
builder.BuilderLoggerFactory.CreateLogger<TypeLoader>(), profilingLogger);
builder.Services.AddUnique<ILogger>(logger);
builder.Services.AddUnique<ILoggerFactory>(builder.BuilderLoggerFactory);
builder.Services.AddUnique<IUmbracoBootPermissionChecker>(_umbracoBootPermissionChecker);
builder.Services.AddUnique<IProfiler>(Profiler);
builder.Services.AddUnique<IProfilingLogger>(profilingLogger);
builder.Services.AddUnique<IMainDom>(MainDom);
builder.Services.AddUnique<AppCaches>(AppCaches);
builder.Services.AddUnique<IRequestCache>(AppCaches.RequestCache);
builder.Services.AddUnique<TypeLoader>(builder.TypeLoader);
builder.Services.AddUnique<ITypeFinder>(TypeFinder);
builder.Services.AddUnique<IIOHelper>(IOHelper);
builder.Services.AddUnique<IUmbracoVersion>(UmbracoVersion);
builder.Services.AddUnique<IDbProviderFactoryCreator>(DbProviderFactoryCreator);
builder.Services.AddUnique<IHostingEnvironment>(HostingEnvironment);
builder.Services.AddUnique<IBackOfficeInfo>(BackOfficeInfo);
builder.Services.AddUnique<IRuntime, CoreRuntime>();
// NOTE: This instance of IUmbracoDatabaseFactory is only used to determine runtime state.
var bootstrapDatabaseFactory = CreateBootstrapDatabaseFactory(builder.BuilderLoggerFactory);
// after bootstrapping we let the container wire up for us.
builder.Services.AddUnique<IUmbracoDatabaseFactory, UmbracoDatabaseFactory>();
builder.Services.AddUnique<ISqlContext>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().SqlContext);
builder.Services.AddUnique<IBulkSqlInsertProvider>(factory => factory.GetRequiredService<IUmbracoDatabaseFactory>().BulkSqlInsertProvider);
// re-create the state object with the essential services
_state = new RuntimeState(_globalSettings, UmbracoVersion, bootstrapDatabaseFactory, builder.BuilderLoggerFactory.CreateLogger<RuntimeState>());
builder.Services.AddUnique<IRuntimeState>(_state);
// run handlers
OnRuntimeEssentials(builder, AppCaches, builder.TypeLoader, bootstrapDatabaseFactory);
// determine our runtime level
DetermineRuntimeLevel(bootstrapDatabaseFactory);
DetermineRuntimeLevel(bootstrapDatabaseFactory, logger, profilingLogger);
}
finally
catch (Exception e)
{
// TODO: This can move to an UmbracoBuilder extension e.g. WithComposers
// TODO: Also we're approaching the point CoreRuntimeBootstrapper can be removed entirely.
// always run composers
RunComposers(builder.TypeLoader, builder);
var bfe = e as BootFailedException ?? new BootFailedException("Boot failed.", e);
if (_state != null)
{
_state.Level = RuntimeLevel.BootFailed;
_state.BootFailedException = bfe;
}
timer?.Fail(exception: bfe); // be sure to log the exception - even if we repeat ourselves
Debugger.Break();
}
}
catch (Exception e)
{
var bfe = e as BootFailedException ?? new BootFailedException("Boot failed.", e);
if (_state != null)
{
_state.Level = RuntimeLevel.BootFailed;
_state.BootFailedException = bfe;
}
timer?.Fail(exception: bfe); // be sure to log the exception - even if we repeat ourselves
Debugger.Break();
// throwing here can cause w3wp to hard-crash and we want to avoid it.
// instead, we're logging the exception and setting level to BootFailed.
// various parts of Umbraco such as UmbracoModule and UmbracoDefaultOwinStartup
// understand this and will nullify themselves, while UmbracoModule will
// throw a BootFailedException for every requests.
}
}
protected virtual void ConfigureUnhandledException()
protected virtual void ConfigureUnhandledException(ILogger logger)
{
//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
@@ -248,39 +208,25 @@ namespace Umbraco.Core.Runtime
var msg = "Unhandled exception in AppDomain";
if (isTerminating) msg += " (terminating)";
msg += ".";
Logger.LogError(exception, msg);
logger.LogError(exception, msg);
};
}
private void RunComposers(TypeLoader typeLoader, IUmbracoBuilder builder)
private void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory, ILogger logger, IProfilingLogger profilingLogger)
{
// get composers, and compose
var composerTypes = ResolveComposerTypes(typeLoader);
IEnumerable<Attribute> enableDisableAttributes;
using (ProfilingLogger.DebugDuration<CoreRuntimeBootstrapper>("Scanning enable/disable composer attributes"))
{
enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
}
var composers = new Composers(builder, composerTypes, enableDisableAttributes, RuntimeLoggerFactory.CreateLogger<Composers>(), ProfilingLogger);
composers.Compose();
}
private void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory)
{
using var timer = ProfilingLogger.DebugDuration<CoreRuntimeBootstrapper>("Determining runtime level.", "Determined.");
using var timer = profilingLogger.DebugDuration<CoreRuntimeBootstrapper>("Determining runtime level.", "Determined.");
try
{
_state.DetermineRuntimeLevel();
Logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason);
logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason);
if (_state.Level == RuntimeLevel.Upgrade)
{
Logger.LogDebug("Configure database factory for upgrades.");
logger.LogDebug("Configure database factory for upgrades.");
databaseFactory.ConfigureForUpgrade();
}
}
@@ -293,51 +239,18 @@ namespace Umbraco.Core.Runtime
}
}
private IEnumerable<Type> ResolveComposerTypes(TypeLoader typeLoader)
{
using (var timer = ProfilingLogger.TraceDuration<CoreRuntimeBootstrapper>("Resolving composer types.", "Resolved."))
{
try
{
return GetComposerTypes(typeLoader);
}
catch
{
timer?.Fail();
throw;
}
}
}
#region Getters
// getters can be implemented by runtimes inheriting from CoreRuntime
/// <summary>
/// Gets all composer types.
/// </summary>
protected virtual IEnumerable<Type> GetComposerTypes(TypeLoader typeLoader)
=> typeLoader.GetTypes<IComposer>();
/// <summary>
/// Returns the application path of the site/solution
/// </summary>
/// <returns></returns>
/// <remarks>
/// By default is null which means it's not running in any virtual folder. If the site is running in a virtual folder, this
/// can be overridden and the virtual path returned (i.e. /mysite/)
/// </remarks>
protected virtual string GetApplicationRootPath()
=> null;
/// <summary>
/// Creates the database factory.
/// </summary>
/// <remarks>This is strictly internal, for tests only.</remarks>
protected internal virtual IUmbracoDatabaseFactory CreateBootstrapDatabaseFactory()
protected internal virtual IUmbracoDatabaseFactory CreateBootstrapDatabaseFactory(ILoggerFactory runtimeLoggerFactory)
=> new UmbracoDatabaseFactory(
RuntimeLoggerFactory.CreateLogger<UmbracoDatabaseFactory>(),
RuntimeLoggerFactory,
runtimeLoggerFactory.CreateLogger<UmbracoDatabaseFactory>(),
runtimeLoggerFactory,
Options.Create(_globalSettings),
Options.Create(_connectionStrings),
new Lazy<IMapperCollection>(() => new MapperCollection(Enumerable.Empty<BaseMapper>())),
@@ -348,14 +261,14 @@ namespace Umbraco.Core.Runtime
#region Events
protected void OnRuntimeBoot()
protected void OnRuntimeBoot(IProfilingLogger profilingLogger)
{
RuntimeBooting?.Invoke(this, ProfilingLogger);
RuntimeBooting?.Invoke(this, profilingLogger);
}
protected void OnRuntimeEssentials(IUmbracoBuilder builder, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory)
{
RuntimeEssentials?.Invoke(this, new RuntimeEssentialsEventArgs(builder, databaseFactory));
RuntimeEssentials?.Invoke(this, new RuntimeEssentialsEventArgs(builder, databaseFactory));
}
public event TypedEventHandler<CoreRuntimeBootstrapper, IProfilingLogger> RuntimeBooting;

View File

@@ -78,13 +78,24 @@ namespace Umbraco.Tests.Integration
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
// Create the core runtime
var bootstrapper = new CoreRuntimeBootstrapper(globalSettings, connectionStrings, testHelper.GetUmbracoVersion(),
testHelper.IOHelper, testHelper.ConsoleLoggerFactory, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker,
testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator,
testHelper.MainDom, testHelper.GetTypeFinder(), AppCaches.NoCache);
var bootstrapper = new CoreRuntimeBootstrapper(
globalSettings,
connectionStrings,
testHelper.GetUmbracoVersion(),
testHelper.IOHelper,
testHelper.Profiler,
testHelper.UmbracoBootPermissionChecker,
testHelper.GetHostingEnvironment(),
testHelper.GetBackOfficeInfo(),
testHelper.DbProviderFactoryCreator,
testHelper.MainDom,
testHelper.GetTypeFinder(),
AppCaches.NoCache
);
var builder = new UmbracoBuilder(services, Mock.Of<IConfiguration>());
var builder = new UmbracoBuilder(services, Mock.Of<IConfiguration>(), testHelper.ConsoleLoggerFactory);
bootstrapper.Configure(builder);
builder.AddComposers();
builder.Build();
Assert.IsTrue(bootstrapper.MainDom.IsMainDom);
@@ -126,7 +137,7 @@ namespace Umbraco.Tests.Integration
// Add it!
var builder = new UmbracoBuilder(services, hostContext.Configuration);
var builder = new UmbracoBuilder(services, hostContext.Configuration, testHelper.ConsoleLoggerFactory);
builder.AddConfiguration();
builder.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration, UmbracoCoreServiceCollectionExtensions.GetCoreRuntime);
});
@@ -166,7 +177,7 @@ namespace Umbraco.Tests.Integration
services.AddRequiredNetCoreServices(testHelper, webHostEnvironment);
// Add it!
var builder = new UmbracoBuilder(services, hostContext.Configuration);
var builder = new UmbracoBuilder(services, hostContext.Configuration, testHelper.ConsoleLoggerFactory);
builder.AddConfiguration()
.AddUmbracoCore(webHostEnvironment, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), hostContext.Configuration, UmbracoCoreServiceCollectionExtensions.GetCoreRuntime)

View File

@@ -126,7 +126,7 @@ namespace Umbraco.Tests.Integration.TestServerTest
public override void ConfigureServices(IServiceCollection services)
{
var umbracoBuilder = services.AddUmbraco(Configuration);
var umbracoBuilder = services.AddUmbraco(TestHelper.GetWebHostEnvironment(), Configuration);
umbracoBuilder
.AddConfiguration()
.AddTestCore(TestHelper, UseTestLocalDb) // This is the important one!

View File

@@ -231,7 +231,6 @@ namespace Umbraco.Tests.Integration.Testing
connectionStrings,
umbracoVersion,
ioHelper,
loggerFactory,
profiler,
Mock.Of<IUmbracoBootPermissionChecker>(),
hostingEnvironment,
@@ -328,7 +327,7 @@ namespace Umbraco.Tests.Integration.Testing
protected void UseTestLocalDb(CoreRuntimeBootstrapper runtimeBootstrapper, RuntimeEssentialsEventArgs args)
{
// This will create a db, install the schema and ensure the app is configured to run
InstallTestLocalDb(args.DatabaseFactory, runtimeBootstrapper.RuntimeLoggerFactory, runtimeBootstrapper.State, TestHelper.WorkingDirectory);
InstallTestLocalDb(args.DatabaseFactory, TestHelper.ConsoleLoggerFactory, runtimeBootstrapper.State, TestHelper.WorkingDirectory);
TestDBConnectionString = args.DatabaseFactory.ConnectionString;
InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString;

View File

@@ -81,7 +81,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer1, Composer2, Composer4>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
// 2 is Core and requires 4
// 3 is User
@@ -121,7 +121,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer1, Composer2, Composer3, Composer4>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
// 2 is Core and requires 4
// 3 is User - stays with RuntimeLevel.Run
@@ -137,7 +137,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer20, Composer21>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
// 21 is required by 20
// => reorder components accordingly
@@ -152,7 +152,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer22, Composer24, Composer25>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
// i23 requires 22
// 24, 25 implement i23
@@ -169,7 +169,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer1, Composer2, Composer3>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
try
{
@@ -192,7 +192,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = TypeArray<Composer2, Composer4, Composer13>();
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
// 2 is Core and requires 4
// 13 is required by 1
@@ -229,7 +229,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) };
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Assert.IsEmpty(Composed);
composers.Compose();
@@ -255,7 +255,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) };
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(2, Composed.Count);
@@ -270,7 +270,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) };
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(3, Composed.Count);
@@ -287,7 +287,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) };
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
var builder = composition.WithCollectionBuilder<ComponentCollectionBuilder>();
@@ -306,32 +306,32 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer10) };
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(1, Composed.Count);
Assert.AreEqual(typeof(Composer10), Composed[0]);
types = new[] { typeof(Composer11) };
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
var requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer2) };
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer12) };
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(1, Composed.Count);
@@ -345,7 +345,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var composition = new UmbracoBuilder(register, Mock.Of<IConfiguration>());
var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(2, Composed.Count);
@@ -361,13 +361,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var types = new[] { typeof(Composer26) };
var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) };
var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(0, Composed.Count); // 26 gone
types = new[] { typeof(Composer26), typeof(Composer27) }; // 26 disabled by assembly attribute, enabled by 27
composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<ILogger<Composers>>());
Composed.Clear();
composers.Compose();
Assert.AreEqual(2, Composed.Count); // both
@@ -388,7 +388,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Components
var allComposers = typeLoader.GetTypes<IComposer>().ToList();
var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList();
var composers = new Composers(builder, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>(), Mock.Of<IProfilingLogger>());
var composers = new Composers(builder, types, Enumerable.Empty<Attribute>(), Mock.Of<ILogger<Composers>>());
var requirements = composers.GetRequirements();
var report = Composers.GetComposersReport(requirements);
Console.WriteLine(report);

View File

@@ -5,23 +5,17 @@ using System.Web.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Runtime;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Tests.Common;
using Umbraco.Tests.Common.Builders;
using Umbraco.Tests.PublishedContent;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Stubs;
@@ -31,7 +25,6 @@ using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.Runtime;
using Umbraco.Web.WebApi;
using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.Routing
@@ -53,15 +46,6 @@ namespace Umbraco.Tests.Routing
HostingEnvironment);
}
public class TestRuntimeBootstrapper : CoreRuntimeBootstrapper
{
public TestRuntimeBootstrapper(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
: base(globalSettings, connectionStrings,umbracoVersion, ioHelper, NullLoggerFactory.Instance, Mock.Of<IProfiler>(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache)
{
}
}
protected override void Compose()
{
base.Compose();

View File

@@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Serilog;
using Smidge;
using Smidge.Nuglify;
using Umbraco.Core;
@@ -32,15 +33,21 @@ namespace Umbraco.Web.Common.Builder
{
public static IUmbracoBuilder AddUmbraco(
this IServiceCollection services,
IConfiguration config)
IWebHostEnvironment webHostEnvironment,
IConfiguration config,
ILoggingConfiguration loggingConfig = null,
ILoggerFactory loggerFactory = null)
{
if (services is null) throw new ArgumentNullException(nameof(services));
if (config is null) throw new ArgumentNullException(nameof(config));
services.AddLazySupport();
var builder = new UmbracoBuilder(services, config);
return builder;
loggingConfig ??= new LoggingConfiguration(Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs"));
services.AddLogger(loggingConfig, config);
loggerFactory ??= LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false));
return new UmbracoBuilder(services, config, loggerFactory);
}
public static IUmbracoBuilder AddConfiguration(this IUmbracoBuilder builder)

View File

@@ -107,7 +107,7 @@ namespace Umbraco.Extensions
var backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings);
var profiler = GetWebProfiler(hostingEnvironment);
builder.Services.AddLogger(hostingEnvironment, loggingConfiguration, configuration);
builder.Services.AddLogger(loggingConfiguration, configuration);
var loggerFactory = builder.Services.BuildServiceProvider().GetService<ILoggerFactory>();
var umbracoVersion = new UmbracoVersion();
@@ -128,6 +128,17 @@ namespace Umbraco.Extensions
bootstrapper.Configure(builder);
builder.AddComposers();
return builder;
}
public static IUmbracoBuilder AddComposers(this IUmbracoBuilder builder)
{
var composerTypes = builder.TypeLoader.GetTypes<IComposer>();
var enableDisable = builder.TypeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
new Composers(builder, composerTypes, enableDisable, builder.BuilderLoggerFactory.CreateLogger<Composers>()).Compose();
return builder;
}
@@ -248,7 +259,6 @@ namespace Umbraco.Extensions
connectionStrings,
umbracoVersion,
ioHelper,
loggerFactory,
profiler,
new AspNetCoreBootPermissionsChecker(),
hostingEnvironment,
@@ -268,12 +278,11 @@ namespace Umbraco.Extensions
/// <param name="hostingEnvironment"></param>
public static IServiceCollection AddLogger(
this IServiceCollection services,
IHostingEnvironment hostingEnvironment,
ILoggingConfiguration loggingConfiguration,
IConfiguration configuration)
{
// Create a serilog logger
var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, configuration);
var logger = SerilogLogger.CreateWithDefaultConfiguration(loggingConfiguration, configuration);
// This is nessasary to pick up all the loggins to MS ILogger.
Log.Logger = logger.SerilogLog;

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Web.UI.NetCore
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
var umbracoBuilder = services.AddUmbraco(_config);
var umbracoBuilder = services.AddUmbraco(_env, _config);
umbracoBuilder
.AddAllBackOfficeComponents(_env)
.AddUmbracoWebsite()

View File

@@ -44,8 +44,21 @@ namespace Umbraco.Web
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker();
return new CoreRuntimeBootstrapper(globalSettings, connectionStrings,umbracoVersion, ioHelper, loggerFactory, profiler, umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom,
GetTypeFinder(hostingEnvironment, logger, profiler), appCaches);
return new CoreRuntimeBootstrapper(
globalSettings,
connectionStrings,
umbracoVersion,
ioHelper,
profiler,
umbracoBootPermissionChecker,
hostingEnvironment,
backOfficeInfo,
dbProviderFactoryCreator,
mainDom,
GetTypeFinder(hostingEnvironment, logger, profiler),
appCaches
);
}

View File

@@ -59,7 +59,7 @@ namespace Umbraco.Web
var loggingConfiguration = new LoggingConfiguration(
Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "App_Data\\Logs"));
var ioHelper = new IOHelper(hostingEnvironment);
var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, new ConfigurationRoot(new List<IConfigurationProvider>()));
var logger = SerilogLogger.CreateWithDefaultConfiguration(loggingConfiguration, new ConfigurationRoot(new List<IConfigurationProvider>()));
var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, _loggerFactory.CreateLogger<AspNetBackOfficeInfo>(), Options.Create(webRoutingSettings));
var profiler = GetWebProfiler(hostingEnvironment);