2020-03-13 18:44:58 +11: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-02-27 11:48:38 +01:00
using Microsoft.Extensions.Hosting ;
2020-02-25 08:56:58 +01:00
using Umbraco.Composing ;
2020-03-16 14:02:08 +01:00
using Umbraco.Configuration ;
2020-02-24 16:18:47 +01:00
using Umbraco.Core ;
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-02-18 08:32:06 +01:00
{
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-25 18:21:44 +11:00
return services . AddUmbracoCore ( webHostEnvironment , umbContainer , Assembly . GetEntryAssembly ());
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-03-13 19:10:21 +11: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-13 19:10:21 +11:00
services . AddSingleton < IHttpContextAccessor , HttpContextAccessor >();
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-25 18:21:44 +11:00
private static void 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-23 15:50:01 +11: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-23 15:50:01 +11: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-24 12:11:46 +11:00
() => services . BuildServiceProvider (). GetService < IRequestCache >(), coreDebug , ioHelper ,
2020-03-23 15:50:01 +11:00
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-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:59:58 +01:00
2020-02-18 08:32:06 +01:00
}
}