2020-03-25 20:42:02 +01:00
using System ;
using System.Data.Common ;
using System.Reflection ;
2020-02-24 16:18:47 +01:00
using Microsoft.AspNetCore.Hosting ;
using Microsoft.AspNetCore.Http ;
2020-03-16 14:02:08 +01:00
using Microsoft.Extensions.Configuration ;
2020-02-18 08:32:06 +01:00
using Microsoft.Extensions.DependencyInjection ;
2020-03-24 10:51:53 +01:00
using Smidge ;
2020-03-30 21:27:35 +02:00
using Smidge.Nuglify ;
2020-02-25 08:56:58 +01:00
using Umbraco.Composing ;
2020-03-16 14:02:08 +01:00
using Umbraco.Configuration ;
2020-03-16 19:14:04 +01:00
using Umbraco.Core ;
2020-02-24 16:18:47 +01:00
using Umbraco.Core.Cache ;
2020-03-13 18:44:58 +11:00
using Umbraco.Core.Composing ;
2020-02-24 16:18:47 +01:00
using Umbraco.Core.Configuration ;
using Umbraco.Core.IO ;
using Umbraco.Core.Logging ;
using Umbraco.Core.Logging.Serilog ;
2020-03-13 18:44:58 +11:00
using Umbraco.Core.Persistence ;
2020-02-25 08:56:58 +01:00
using Umbraco.Core.Runtime ;
2020-03-31 12:22:11 +02:00
using Umbraco.Web.Common.AspNetCore ;
2020-03-25 05:39:25 +01:00
using Umbraco.Web.Common.Runtime.Profiler ;
2020-02-18 08:32:06 +01:00
2020-03-31 12:22:11 +02:00
namespace Umbraco.Web.Common.Extensions
2020-02-18 08:32:06 +01:00
{
2020-03-24 14:48:32 +11:00
public static class UmbracoCoreServiceCollectionExtensions
2020-02-18 08:32:06 +01:00
{
2020-03-24 14:48:32 +11:00
/// <summary>
/// Adds the Umbraco Configuration requirements
/// </summary>
/// <param name="services"></param>
2020-03-25 18:21:44 +11:00
/// <param name="configuration"></param>
2020-03-24 14:48:32 +11:00
/// <returns></returns>
2020-03-25 18:21:44 +11:00
public static IServiceCollection AddUmbracoConfiguration ( this IServiceCollection services , IConfiguration configuration )
2020-03-17 17:56:00 +01:00
{
2020-03-25 18:21:44 +11:00
if ( configuration = = null ) throw new ArgumentNullException ( nameof ( configuration ) ) ;
2020-03-23 16:39:27 +11:00
2020-03-17 17:56:00 +01:00
var configsFactory = new AspNetCoreConfigsFactory ( configuration ) ;
var configs = configsFactory . Create ( ) ;
2020-03-19 18:43:39 +01:00
2020-03-17 17:56:00 +01:00
services . AddSingleton ( configs ) ;
return services ;
}
2020-03-23 15:50:01 +11:00
2020-03-13 18:44:58 +11:00
/// <summary>
2020-03-24 14:48:32 +11:00
/// Adds the Umbraco Back Core requirements
2020-03-13 18:44:58 +11:00
/// </summary>
/// <param name="services"></param>
2020-03-25 18:21:44 +11:00
/// <param name="webHostEnvironment"></param>
2020-03-13 18:44:58 +11:00
/// <returns></returns>
2020-03-25 18:21:44 +11:00
public static IServiceCollection AddUmbracoCore ( this IServiceCollection services , IWebHostEnvironment webHostEnvironment )
2020-03-13 18:44:58 +11:00
{
if ( ! UmbracoServiceProviderFactory . IsActive )
throw new InvalidOperationException ( "Ensure to add UseUmbraco() in your Program.cs after ConfigureWebHostDefaults to enable Umbraco's service provider factory" ) ;
var umbContainer = UmbracoServiceProviderFactory . UmbracoContainer ;
2020-03-26 06:51:23 +01:00
services . AddUmbracoCore ( webHostEnvironment , umbContainer , Assembly . GetEntryAssembly ( ) ) ;
2020-03-25 20:42:02 +01:00
return services ;
2020-03-13 19:10:21 +11:00
}
2020-03-24 14:48:32 +11:00
/// <summary>
/// Adds the Umbraco Back Core requirements
/// </summary>
/// <param name="services"></param>
2020-03-25 18:21:44 +11:00
/// <param name="webHostEnvironment"></param>
2020-03-24 14:48:32 +11:00
/// <param name="umbContainer"></param>
/// <param name="entryAssembly"></param>
/// <returns></returns>
2020-03-25 18:21:44 +11:00
public static IServiceCollection AddUmbracoCore ( this IServiceCollection services , IWebHostEnvironment webHostEnvironment , IRegister umbContainer , Assembly entryAssembly )
2020-02-18 08:32:06 +01:00
{
2020-03-24 11:53:56 +11:00
if ( services is null ) throw new ArgumentNullException ( nameof ( services ) ) ;
2020-03-27 11:39:17 +01:00
var container = umbContainer ;
if ( container is null ) throw new ArgumentNullException ( nameof ( container ) ) ;
2020-03-24 11:53:56 +11:00
if ( entryAssembly is null ) throw new ArgumentNullException ( nameof ( entryAssembly ) ) ;
2020-03-25 15:06:22 +11:00
// Special case! The generic host adds a few default services but we need to manually add this one here NOW because
// we resolve it before the host finishes configuring in the call to CreateCompositionRoot
2020-03-16 14:02:08 +01:00
services . AddSingleton < IHttpContextAccessor , HttpContextAccessor > ( ) ;
2020-02-24 16:18:47 +01:00
2020-03-25 18:21:44 +11:00
CreateCompositionRoot ( services , webHostEnvironment , out var logger , out var configs , out var ioHelper , out var hostingEnvironment , out var backOfficeInfo , out var profiler ) ;
2020-03-13 19:10:21 +11:00
2020-03-24 11:53:56 +11:00
var globalSettings = configs . Global ( ) ;
2020-03-13 18:44:58 +11:00
var umbracoVersion = new UmbracoVersion ( globalSettings ) ;
2020-03-13 19:10:21 +11:00
// TODO: Currently we are not passing in any TypeFinderConfig (with ITypeFinderSettings) which we should do, however
// this is not critical right now and would require loading in some config before boot time so just leaving this as-is for now.
2020-03-24 11:53:56 +11:00
var typeFinder = new TypeFinder ( logger , new DefaultUmbracoAssemblyProvider ( entryAssembly ) ) ;
2020-03-13 19:10:21 +11:00
2020-03-13 18:44:58 +11:00
var coreRuntime = GetCoreRuntime (
2020-03-24 11:53:56 +11:00
configs ,
2020-03-13 18:44:58 +11:00
umbracoVersion ,
2020-03-24 11:53:56 +11:00
ioHelper ,
logger ,
profiler ,
hostingEnvironment ,
backOfficeInfo ,
2020-03-13 19:10:21 +11:00
typeFinder ) ;
2020-03-13 18:44:58 +11:00
2020-03-27 11:39:17 +01:00
var factory = coreRuntime . Configure ( container ) ;
2020-03-13 18:44:58 +11:00
2020-02-18 08:32:06 +01:00
return services ;
}
2020-03-13 18:44:58 +11:00
private static IRuntime GetCoreRuntime ( Configs configs , IUmbracoVersion umbracoVersion , IIOHelper ioHelper , ILogger logger ,
2020-03-13 19:10:21 +11:00
IProfiler profiler , Core . Hosting . IHostingEnvironment hostingEnvironment , IBackOfficeInfo backOfficeInfo ,
ITypeFinder typeFinder )
2020-03-13 18:44:58 +11:00
{
var connectionStringConfig = configs . ConnectionStrings ( ) [ Constants . System . UmbracoConnectionName ] ;
var dbProviderFactoryCreator = new SqlServerDbProviderFactoryCreator (
connectionStringConfig ? . ProviderName ,
DbProviderFactories . GetFactory ) ;
// Determine if we should use the sql main dom or the default
2020-03-23 15:50:01 +11:00
var globalSettings = configs . Global ( ) ;
var connStrings = configs . ConnectionStrings ( ) ;
var appSettingMainDomLock = globalSettings . MainDomLock ;
2020-03-13 18:44:58 +11:00
var mainDomLock = appSettingMainDomLock = = "SqlMainDomLock"
2020-03-23 15:50:01 +11:00
? ( IMainDomLock ) new SqlMainDomLock ( logger , globalSettings , connStrings , dbProviderFactoryCreator )
2020-03-13 18:44:58 +11:00
: new MainDomSemaphoreLock ( logger , hostingEnvironment ) ;
2020-03-25 15:06:22 +11:00
var mainDom = new MainDom ( logger , mainDomLock ) ;
2020-03-13 18:44:58 +11:00
var coreRuntime = new CoreRuntime ( configs , umbracoVersion , ioHelper , logger , profiler , new AspNetCoreBootPermissionsChecker ( ) ,
hostingEnvironment , backOfficeInfo , dbProviderFactoryCreator , mainDom , typeFinder ) ;
return coreRuntime ;
}
2020-02-25 08:56:58 +01:00
2020-03-26 06:51:23 +01:00
private static IServiceCollection CreateCompositionRoot ( IServiceCollection services , IWebHostEnvironment webHostEnvironment ,
2020-03-24 11:53:56 +11:00
out ILogger logger , out Configs configs , out IIOHelper ioHelper , out Core . Hosting . IHostingEnvironment hostingEnvironment ,
out IBackOfficeInfo backOfficeInfo , out IProfiler profiler )
2020-02-24 16:18:47 +01:00
{
2020-03-25 17:35:43 +11:00
// TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
2020-02-24 16:18:47 +01:00
var serviceProvider = services . BuildServiceProvider ( ) ;
2020-03-13 19:10:21 +11:00
var httpContextAccessor = serviceProvider . GetRequiredService < IHttpContextAccessor > ( ) ;
2020-02-24 16:18:47 +01:00
2020-03-24 11:53:56 +11:00
configs = serviceProvider . GetService < Configs > ( ) ;
2020-03-23 16:39:27 +11:00
if ( configs = = null )
throw new InvalidOperationException ( $"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}" ) ;
2020-02-24 16:18:47 +01:00
2020-03-16 19:14:04 +01:00
var hostingSettings = configs . Hosting ( ) ;
var coreDebug = configs . CoreDebug ( ) ;
var globalSettings = configs . Global ( ) ;
2020-02-24 16:18:47 +01:00
2020-03-25 15:06:22 +11:00
hostingEnvironment = new AspNetCoreHostingEnvironment ( hostingSettings , webHostEnvironment , httpContextAccessor ) ;
2020-03-24 11:53:56 +11:00
ioHelper = new IOHelper ( hostingEnvironment , globalSettings ) ;
logger = SerilogLogger . CreateWithDefaultConfiguration ( hostingEnvironment ,
2020-03-18 19:17:51 +01:00
new AspNetCoreSessionIdResolver ( httpContextAccessor ) ,
2020-03-25 17:35:43 +11:00
// TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
2020-03-18 19:17:51 +01:00
( ) = > services . BuildServiceProvider ( ) . GetService < IRequestCache > ( ) , coreDebug , ioHelper ,
new AspNetCoreMarchal ( ) ) ;
2020-03-12 16:56:39 +01:00
2020-03-24 14:47:10 +11:00
backOfficeInfo = new AspNetCoreBackOfficeInfo ( globalSettings ) ;
2020-03-26 06:59:58 +01:00
profiler = GetWebProfiler ( hostingEnvironment , httpContextAccessor ) ;
2020-02-24 16:18:47 +01:00
2020-02-25 08:56:58 +01:00
Current . Initialize ( logger , configs , ioHelper , hostingEnvironment , backOfficeInfo , profiler ) ;
2020-03-16 14:02:08 +01:00
return services ;
2020-02-24 16:18:47 +01:00
}
2020-03-24 10:51:53 +01:00
2020-03-25 20:42:02 +01:00
public static IServiceCollection AddUmbracoRuntimeMinifier ( this IServiceCollection services ,
2020-03-24 17:34:34 +01:00
IConfiguration configuration )
2020-03-24 10:51:53 +01:00
{
2020-03-31 10:47:08 +02:00
services . AddSmidge ( configuration . GetSection ( Constants . Configuration . ConfigRuntimeMinification ) ) ;
2020-03-30 21:27:35 +02:00
services . AddSmidgeNuglify ( ) ;
2020-03-24 10:51:53 +01:00
return services ;
}
2020-03-13 18:44:58 +11:00
2020-03-25 05:39:25 +01:00
private static IProfiler GetWebProfiler ( Umbraco . Core . Hosting . IHostingEnvironment hostingEnvironment , IHttpContextAccessor httpContextAccessor )
{
// create and start asap to profile boot
if ( ! hostingEnvironment . IsDebugMode )
{
// should let it be null, that's how MiniProfiler is meant to work,
// but our own IProfiler expects an instance so let's get one
return new VoidProfiler ( ) ;
}
var webProfiler = new WebProfiler ( httpContextAccessor ) ;
2020-03-29 22:35:52 +02:00
webProfiler . StartBoot ( ) ;
2020-03-25 05:39:25 +01:00
return webProfiler ;
}
2020-03-13 18:44:58 +11:00
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
{
public void ThrowIfNotPermissions ( )
{
// nothing to check
}
}
2020-03-24 14:48:32 +11:00
2020-03-26 06:51:23 +01:00
2020-02-18 08:32:06 +01:00
}
}