Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/ab5820-webprofiler-aspnetcore
# Conflicts: # src/Umbraco.Web.UI.NetCore/Startup.cs
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -164,3 +164,5 @@ build/temp/
|
||||
# eof
|
||||
/src/Umbraco.Web.UI.Client/TESTS-*.xml
|
||||
/src/ApiDocs/api/*
|
||||
/src/Umbraco.Web.UI.NetCore/wwwroot/Media/*
|
||||
/src/Umbraco.Web.UI.NetCore/wwwroot/is-cache/*
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Configuration
|
||||
|
||||
public AspNetCoreConfigsFactory(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_configuration = configuration ?? throw new System.ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
public Configs Create()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -42,7 +43,14 @@ namespace Umbraco.Core.Composing
|
||||
{
|
||||
foreach(var target in _targetAssemblies)
|
||||
{
|
||||
referenceItems.Add(Assembly.Load(target));
|
||||
try
|
||||
{
|
||||
referenceItems.Add(Assembly.Load(target));
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// occurs if we cannot load this ... for example in a test project where we aren't currently referencing Umbraco.Web, etc...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IOHelper(IHostingEnvironment hostingEnvironment, IGlobalSettings globalSettings)
|
||||
{
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
public class ConsoleLogger : ILogger
|
||||
{
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines the logging service.
|
||||
/// </summary>
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Web
|
||||
|
||||
public UriUtility(IHostingEnvironment hostingEnvironment)
|
||||
{
|
||||
if (hostingEnvironment is null) throw new ArgumentNullException(nameof(hostingEnvironment));
|
||||
ResetAppDomainAppVirtualPath(hostingEnvironment);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends the <see cref="IHostBuilder"/> to enable Umbraco to be used as the service container.
|
||||
/// </summary>
|
||||
public static class HostBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Assigns a custom service provider factory to use Umbraco's container
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <returns></returns>
|
||||
public static IHostBuilder UseUmbraco(this IHostBuilder builder)
|
||||
{
|
||||
return builder.UseServiceProviderFactory(new UmbracoServiceProviderFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,13 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LightInjectContainer"/> with a LightInject container.
|
||||
/// </summary>
|
||||
protected LightInjectContainer(ServiceContainer container)
|
||||
public LightInjectContainer(ServiceContainer container)
|
||||
{
|
||||
Container = container;
|
||||
Container = ConfigureContainer(container);
|
||||
}
|
||||
|
||||
//TODO: The Create methods can die when net framework is gone
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LightInjectContainer"/> class.
|
||||
/// </summary>
|
||||
@@ -33,7 +35,12 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
protected static ServiceContainer CreateServiceContainer()
|
||||
{
|
||||
var container = new ServiceContainer(new ContainerOptions { EnablePropertyInjection = false });
|
||||
ConfigureContainer(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
private static ServiceContainer ConfigureContainer(ServiceContainer container)
|
||||
{
|
||||
// note: the block below is disabled, as it is too LightInject-specific
|
||||
//
|
||||
// supports annotated constructor injections
|
||||
@@ -84,7 +91,7 @@ namespace Umbraco.Core.Composing.LightInject
|
||||
/// <summary>
|
||||
/// Gets the LightInject container.
|
||||
/// </summary>
|
||||
protected ServiceContainer Container { get; }
|
||||
public ServiceContainer Container { get; }
|
||||
|
||||
/// <inheritdoc cref="IRegister"/>
|
||||
/// <inheritdoc cref="IFactory"/>
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
using System;
|
||||
using LightInject;
|
||||
using LightInject.Microsoft.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Composing.LightInject;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates the container.
|
||||
/// </summary>
|
||||
public static class RegisterFactory
|
||||
{
|
||||
//TODO: This can die when net framework is gone
|
||||
|
||||
// cannot use typeof().AssemblyQualifiedName on the web container - we don't reference it
|
||||
// a normal Umbraco site should run on the web container, but an app may run on the core one
|
||||
private const string CoreLightInjectContainerTypeName = "Umbraco.Core.Composing.LightInject.LightInjectContainer,Umbraco.Core";
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using LightInject;
|
||||
using LightInject.Microsoft.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using Umbraco.Core.Composing.LightInject;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to create Umbraco's container and cross-wire it up before the applicaton starts
|
||||
/// </summary>
|
||||
public class UmbracoServiceProviderFactory : IServiceProviderFactory<IServiceContainer>
|
||||
{
|
||||
public UmbracoServiceProviderFactory(ServiceContainer container)
|
||||
{
|
||||
_container = new LightInjectContainer(container);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an ASP.NET Core compatible service container
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ServiceContainer CreateServiceContainer() => new ServiceContainer(ContainerOptions.Default.Clone().WithMicrosoftSettings().WithAspNetCoreSettings());
|
||||
|
||||
/// <summary>
|
||||
/// Default ctor for use in Host Builder configuration
|
||||
/// </summary>
|
||||
public UmbracoServiceProviderFactory()
|
||||
{
|
||||
var container = CreateServiceContainer();
|
||||
UmbracoContainer = _container = new LightInjectContainer(container);
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
// see here for orig lightinject version https://github.com/seesharper/LightInject.Microsoft.DependencyInjection/blob/412566e3f70625e6b96471db5e1f7cd9e3e1eb18/src/LightInject.Microsoft.DependencyInjection/LightInject.Microsoft.DependencyInjection.cs#L263
|
||||
// we don't really need all that, we're manually creating our container with the correct options and that
|
||||
// is what we'll return in CreateBuilder
|
||||
|
||||
IServiceCollection _services;
|
||||
readonly LightInjectContainer _container;
|
||||
|
||||
internal LightInjectContainer GetContainer() => _container;
|
||||
|
||||
/// <summary>
|
||||
/// When the empty ctor is used this returns if this factory is active
|
||||
/// </summary>
|
||||
public static bool IsActive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// When the empty ctor is used this returns the created IRegister
|
||||
/// </summary>
|
||||
public static IRegister UmbracoContainer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create the container with the required settings for aspnetcore3
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public IServiceContainer CreateBuilder(IServiceCollection services)
|
||||
{
|
||||
_services = services;
|
||||
return _container.Container;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This cross-wires the container just before the application calls "Configure"
|
||||
/// </summary>
|
||||
/// <param name="containerBuilder"></param>
|
||||
/// <returns></returns>
|
||||
public IServiceProvider CreateServiceProvider(IServiceContainer containerBuilder)
|
||||
{
|
||||
var provider = containerBuilder.CreateServiceProvider(_services);
|
||||
return provider;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Data.Common;
|
||||
using StackExchange.Profiling.Internal;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
|
||||
public interface IDbProviderFactoryCreator
|
||||
{
|
||||
DbProviderFactory CreateFactory();
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
public class SqlServerDbProviderFactoryCreator : IDbProviderFactoryCreator
|
||||
{
|
||||
private readonly string _defaultProviderName;
|
||||
private readonly Func<string, DbProviderFactory> _getFactory;
|
||||
|
||||
public SqlServerDbProviderFactoryCreator(string defaultProviderName, Func<string, DbProviderFactory> getFactory)
|
||||
{
|
||||
_defaultProviderName = defaultProviderName;
|
||||
_getFactory = getFactory;
|
||||
}
|
||||
|
||||
public DbProviderFactory CreateFactory() => CreateFactory(_defaultProviderName);
|
||||
|
||||
public DbProviderFactory CreateFactory(string providerName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(providerName)) return null;
|
||||
return _getFactory(providerName);
|
||||
}
|
||||
|
||||
// gets the sql syntax provider that corresponds, from attribute
|
||||
public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName)
|
||||
{
|
||||
return providerName switch
|
||||
{
|
||||
Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"),
|
||||
Constants.DbProviderNames.SqlServer => new SqlServerSyntaxProvider(),
|
||||
_ => throw new InvalidOperationException($"Unknown provider name \"{providerName}\""),
|
||||
};
|
||||
}
|
||||
|
||||
public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName)
|
||||
{
|
||||
switch (providerName)
|
||||
{
|
||||
case Constants.DbProviderNames.SqlCe:
|
||||
throw new NotSupportedException("SqlCe is not supported");
|
||||
case Constants.DbProviderNames.SqlServer:
|
||||
return new SqlServerBulkSqlInsertProvider();
|
||||
default:
|
||||
return new BasicBulkSqlInsertProvider();
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateDatabase()
|
||||
{
|
||||
throw new NotSupportedException("Embedded databases are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,8 @@ namespace Umbraco.Core.Runtime
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IBackOfficeInfo backOfficeInfo,
|
||||
IDbProviderFactoryCreator dbProviderFactoryCreator,
|
||||
IMainDom mainDom)
|
||||
IMainDom mainDom,
|
||||
ITypeFinder typeFinder)
|
||||
{
|
||||
IOHelper = ioHelper;
|
||||
Configs = configs;
|
||||
@@ -55,6 +56,7 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
Logger = logger;
|
||||
MainDom = mainDom;
|
||||
TypeFinder = typeFinder;
|
||||
|
||||
_globalSettings = Configs.Global();
|
||||
_connectionStrings = configs.ConnectionStrings();
|
||||
@@ -95,7 +97,7 @@ namespace Umbraco.Core.Runtime
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
protected ITypeFinder TypeFinder { get; private set; }
|
||||
protected ITypeFinder TypeFinder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IIOHelper"/>
|
||||
@@ -116,11 +118,6 @@ namespace Umbraco.Core.Runtime
|
||||
// create and register the essential services
|
||||
// ie the bare minimum required to boot
|
||||
|
||||
|
||||
TypeFinder = GetTypeFinder();
|
||||
if (TypeFinder == null)
|
||||
throw new InvalidOperationException($"The object returned from {nameof(GetTypeFinder)} cannot be null");
|
||||
|
||||
// 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.
|
||||
// note that this REQUIRES that perWebRequestScope has NOT been enabled yet, else
|
||||
@@ -260,11 +257,6 @@ namespace Umbraco.Core.Runtime
|
||||
return _factory;
|
||||
}
|
||||
|
||||
private IUmbracoVersion GetUmbracoVersion(IGlobalSettings globalSettings)
|
||||
{
|
||||
return new UmbracoVersion(globalSettings);
|
||||
}
|
||||
|
||||
protected virtual void ConfigureUnhandledException()
|
||||
{
|
||||
//take care of unhandled exceptions - there is nothing we can do to
|
||||
@@ -371,28 +363,6 @@ namespace Umbraco.Core.Runtime
|
||||
protected virtual IEnumerable<Type> GetComposerTypes(TypeLoader typeLoader)
|
||||
=> typeLoader.GetTypes<IComposer>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ITypeFinder GetTypeFinder()
|
||||
// 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.
|
||||
=> new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
|
||||
// GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website
|
||||
// in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since
|
||||
// the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly()
|
||||
// which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK.
|
||||
// If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own
|
||||
// code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting
|
||||
// from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance
|
||||
// of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point
|
||||
// assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one.
|
||||
// For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are
|
||||
// getting rid of netframework.
|
||||
Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application caches.
|
||||
/// </summary>
|
||||
|
||||
@@ -31,9 +31,10 @@ namespace Umbraco.Web.Runtime
|
||||
IBackOfficeInfo backOfficeInfo,
|
||||
IDbProviderFactoryCreator dbProviderFactoryCreator,
|
||||
IMainDom mainDom,
|
||||
ITypeFinder typeFinder,
|
||||
IRequestCache requestCache,
|
||||
IUmbracoBootPermissionChecker umbracoBootPermissionChecker):
|
||||
base(configs, umbracoVersion, ioHelper, logger, profiler ,umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom)
|
||||
base(configs, umbracoVersion, ioHelper, logger, profiler ,umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder)
|
||||
{
|
||||
_requestCache = requestCache;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.8.14" />
|
||||
<PackageReference Include="LightInject" Version="6.3.2" />
|
||||
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
|
||||
<PackageReference Include="LightInject.Microsoft.DependencyInjection" Version="3.3.0" />
|
||||
<PackageReference Include="LightInject.Microsoft.Hosting" Version="1.2.0" />
|
||||
<PackageReference Include="Markdown" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" />
|
||||
@@ -57,6 +60,9 @@
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests.Benchmarks</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests.Integration</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
35
src/Umbraco.Tests.Common/Assertions.cs
Normal file
35
src/Umbraco.Tests.Common/Assertions.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using LightInject;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Tests.Common.Composing;
|
||||
|
||||
namespace Umbraco.Tests.Common
|
||||
{
|
||||
public class Assertions
|
||||
{
|
||||
public static void AssertContainer(ServiceContainer container, bool reportOnly = false)
|
||||
{
|
||||
var results = container.Validate().ToList();
|
||||
foreach (var resultGroup in results.GroupBy(x => x.Severity).OrderBy(x => x.Key))
|
||||
{
|
||||
Console.WriteLine($"{resultGroup.Key}: {resultGroup.Count()}");
|
||||
}
|
||||
|
||||
foreach (var resultGroup in results.GroupBy(x => x.Severity).OrderBy(x => x.Key))
|
||||
{
|
||||
foreach (var result in resultGroup)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.Write(result.ToText());
|
||||
}
|
||||
}
|
||||
|
||||
if (!reportOnly)
|
||||
Assert.AreEqual(0, results.Count);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ using ServiceMap = System.Collections.Generic.Dictionary<System.Type, System.Col
|
||||
http://twitter.com/bernhardrichter
|
||||
******************************************************************************/
|
||||
|
||||
namespace Umbraco.Tests.Composing
|
||||
namespace Umbraco.Tests.Common.Composing
|
||||
{
|
||||
public static class LightInjectValidation
|
||||
{
|
||||
@@ -110,7 +110,6 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
{
|
||||
var registration = GetServiceRegistration(serviceMap, validationTarget);
|
||||
if (registration == null)
|
||||
{
|
||||
if (validationTarget.ServiceType.IsFunc() || validationTarget.ServiceType.IsLazy())
|
||||
{
|
||||
var serviceType = validationTarget.ServiceType.GenericTypeArguments[0];
|
||||
@@ -118,17 +117,13 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
registration = GetServiceRegistration(serviceMap, underlyingvalidationTarget);
|
||||
|
||||
if (registration != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceMap.ContainsAmbiguousRegistrationFor(serviceType))
|
||||
{
|
||||
result.Add(new ValidationResult("", ValidationSeverity.Ambiguous, underlyingvalidationTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = string.Format(MissingDeferredDependency, validationTarget.ServiceType, underlyingvalidationTarget.ServiceType);
|
||||
var message = string.Format(MissingDeferredDependency, validationTarget.ServiceType, underlyingvalidationTarget.ServiceType);
|
||||
result.Add(new ValidationResult(message, ValidationSeverity.MissingDependency, underlyingvalidationTarget));
|
||||
}
|
||||
}
|
||||
@@ -140,21 +135,14 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
if (registrations.Any()) return;
|
||||
|
||||
// strict: there has to be at least 1
|
||||
string message = string.Format(MissingDeferredDependency, validationTarget.ServiceType, underlyingvalidationTarget.ServiceType);
|
||||
var message = string.Format(MissingDeferredDependency, validationTarget.ServiceType, underlyingvalidationTarget.ServiceType);
|
||||
result.Add(new ValidationResult(message, ValidationSeverity.MissingDependency, underlyingvalidationTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serviceMap.ContainsAmbiguousRegistrationFor(validationTarget.ServiceType))
|
||||
{
|
||||
result.Add(new ValidationResult("", ValidationSeverity.Ambiguous, validationTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(new ValidationResult("", ValidationSeverity.MissingDependency, validationTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
result.Add(new ValidationResult("", ValidationSeverity.Ambiguous, validationTarget));
|
||||
else
|
||||
result.Add(new ValidationResult("", ValidationSeverity.MissingDependency, validationTarget));
|
||||
else
|
||||
{
|
||||
ValidateDisposable(validationTarget, result, registration);
|
||||
@@ -206,24 +194,16 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
private static ServiceRegistration GetServiceRegistration(ServiceMap serviceMap, ValidationTarget validationTarget)
|
||||
{
|
||||
if (!serviceMap.TryGetValue(validationTarget.ServiceType, out var registrations))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (registrations.TryGetValue(string.Empty, out var registration))
|
||||
{
|
||||
return registration;
|
||||
}
|
||||
|
||||
if (registrations.Count == 1)
|
||||
{
|
||||
return registrations.Values.First();
|
||||
}
|
||||
|
||||
if (registrations.TryGetValue(validationTarget.ServiceName, out registration))
|
||||
{
|
||||
return registration;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -231,22 +211,16 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
private static string GetLifetimeName(ILifetime lifetime)
|
||||
{
|
||||
if (lifetime == null)
|
||||
{
|
||||
return "Transient";
|
||||
}
|
||||
return lifetime.GetType().Name;
|
||||
}
|
||||
|
||||
private static int GetLifespan(ILifetime lifetime)
|
||||
{
|
||||
if (lifetime == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (LifeSpans.TryGetValue(lifetime.GetType(), out var lifespan))
|
||||
{
|
||||
return lifespan;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -274,9 +248,7 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
|
||||
|
||||
if (serviceType.GetTypeInfo().IsGenericType && serviceType.GetTypeInfo().ContainsGenericParameters)
|
||||
{
|
||||
ServiceType = serviceType.GetGenericTypeDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -340,9 +312,7 @@ Ensure that 'NameSpace.IBar' is registered with a lifetime that is equal to or h
|
||||
public static bool ContainsAmbiguousRegistrationFor(this ServiceMap serviceMap, Type serviceType)
|
||||
{
|
||||
if (!serviceMap.TryGetValue(serviceType, out var registrations))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return registrations.Count > 1;
|
||||
}
|
||||
}
|
||||
107
src/Umbraco.Tests.Common/Composing/ValidationResultExtensions.cs
Normal file
107
src/Umbraco.Tests.Common/Composing/ValidationResultExtensions.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.Common.Composing
|
||||
{
|
||||
// These are used for Light Inject container validation
|
||||
public static class ValidationResultExtensions
|
||||
{
|
||||
public static string ToText(this ValidationResult result)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
|
||||
text.AppendLine($"{result.Severity}: {WordWrap(result.Message, 120)}");
|
||||
var target = result.ValidationTarget;
|
||||
text.Append("\tsvce: ");
|
||||
text.Append(target.ServiceName);
|
||||
text.Append(target.DeclaringService.ServiceType);
|
||||
if (!target.DeclaringService.ServiceName.IsNullOrWhiteSpace())
|
||||
{
|
||||
text.Append(" '");
|
||||
text.Append(target.DeclaringService.ServiceName);
|
||||
text.Append("'");
|
||||
}
|
||||
|
||||
text.Append(" (");
|
||||
if (target.DeclaringService.Lifetime == null)
|
||||
text.Append("Transient");
|
||||
else
|
||||
text.Append(target.DeclaringService.Lifetime.ToString().TrimStart("LightInject.").TrimEnd("Lifetime"));
|
||||
text.AppendLine(")");
|
||||
text.Append("\timpl: ");
|
||||
text.Append(target.DeclaringService.ImplementingType);
|
||||
text.AppendLine();
|
||||
text.Append("\tparm: ");
|
||||
text.Append(target.Parameter);
|
||||
text.AppendLine();
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static string WordWrap(string text, int width)
|
||||
{
|
||||
int pos, next;
|
||||
var sb = new StringBuilder();
|
||||
var nl = Environment.NewLine;
|
||||
|
||||
// Lucidity check
|
||||
if (width < 1)
|
||||
return text;
|
||||
|
||||
// Parse each line of text
|
||||
for (pos = 0; pos < text.Length; pos = next)
|
||||
{
|
||||
// Find end of line
|
||||
var eol = text.IndexOf(nl, pos, StringComparison.Ordinal);
|
||||
|
||||
if (eol == -1)
|
||||
next = eol = text.Length;
|
||||
else
|
||||
next = eol + nl.Length;
|
||||
|
||||
// Copy this line of text, breaking into smaller lines as needed
|
||||
if (eol > pos)
|
||||
{
|
||||
do
|
||||
{
|
||||
var len = eol - pos;
|
||||
|
||||
if (len > width)
|
||||
len = BreakLine(text, pos, width);
|
||||
|
||||
if (pos > 0)
|
||||
sb.Append("\t\t");
|
||||
sb.Append(text, pos, len);
|
||||
sb.Append(nl);
|
||||
|
||||
// Trim whitespace following break
|
||||
pos += len;
|
||||
|
||||
while (pos < eol && char.IsWhiteSpace(text[pos]))
|
||||
pos++;
|
||||
|
||||
} while (eol > pos);
|
||||
}
|
||||
else sb.Append(nl); // Empty line
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static int BreakLine(string text, int pos, int max)
|
||||
{
|
||||
// Find last whitespace in line
|
||||
var i = max - 1;
|
||||
while (i >= 0 && !char.IsWhiteSpace(text[pos + i]))
|
||||
i--;
|
||||
if (i < 0)
|
||||
return max; // No whitespace found; break at maximum length
|
||||
// Find start of whitespace
|
||||
while (i >= 0 && char.IsWhiteSpace(text[pos + i]))
|
||||
i--;
|
||||
// Return length of text before whitespace
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -12,7 +13,6 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Core.Serialization;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Sync;
|
||||
@@ -27,31 +27,26 @@ namespace Umbraco.Tests.Common
|
||||
/// </summary>
|
||||
public abstract class TestHelperBase
|
||||
{
|
||||
public TestHelperBase()
|
||||
private readonly ITypeFinder _typeFinder;
|
||||
private UriUtility _uriUtility;
|
||||
private IIOHelper _ioHelper;
|
||||
|
||||
public TestHelperBase(Assembly entryAssembly)
|
||||
{
|
||||
SettingsForTests = new SettingsForTests();
|
||||
IOHelper = new IOHelper(GetHostingEnvironment(), SettingsForTests.GenerateMockGlobalSettings());
|
||||
MainDom = new MainDom(Mock.Of<ILogger>(), GetHostingEnvironment(), new MainDomSemaphoreLock(Mock.Of<ILogger>(), GetHostingEnvironment()));
|
||||
UriUtility = new UriUtility(GetHostingEnvironment());
|
||||
SettingsForTests = new SettingsForTests();
|
||||
MainDom = new SimpleMainDom();
|
||||
_typeFinder = new TypeFinder(Mock.Of<ILogger>(), new DefaultUmbracoAssemblyProvider(entryAssembly));
|
||||
}
|
||||
|
||||
public ITypeFinder GetTypeFinder()
|
||||
{
|
||||
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>(),
|
||||
new DefaultUmbracoAssemblyProvider(typeof(TestHelperBase).Assembly));
|
||||
return typeFinder;
|
||||
}
|
||||
public ITypeFinder GetTypeFinder() => _typeFinder;
|
||||
|
||||
public TypeLoader GetMockedTypeLoader()
|
||||
{
|
||||
return new TypeLoader(IOHelper, Mock.Of<ITypeFinder>(), Mock.Of<IAppPolicyCache>(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of<IProfilingLogger>());
|
||||
}
|
||||
|
||||
public Configs GetConfigs()
|
||||
{
|
||||
return GetConfigsFactory().Create();
|
||||
}
|
||||
public Configs GetConfigs() => GetConfigsFactory().Create();
|
||||
|
||||
public IRuntimeState GetRuntimeState()
|
||||
{
|
||||
return new RuntimeState(
|
||||
@@ -67,10 +62,7 @@ namespace Umbraco.Tests.Common
|
||||
|
||||
public abstract IBackOfficeInfo GetBackOfficeInfo();
|
||||
|
||||
public IConfigsFactory GetConfigsFactory()
|
||||
{
|
||||
return new ConfigsFactory();
|
||||
}
|
||||
public IConfigsFactory GetConfigsFactory() => new ConfigsFactory();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current assembly directory.
|
||||
@@ -95,10 +87,27 @@ namespace Umbraco.Tests.Common
|
||||
public abstract IMarchal Marchal { get; }
|
||||
public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings();
|
||||
|
||||
public IIOHelper IOHelper
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ioHelper == null)
|
||||
_ioHelper = new IOHelper(GetHostingEnvironment(), SettingsForTests.GenerateMockGlobalSettings());
|
||||
return _ioHelper;
|
||||
}
|
||||
}
|
||||
|
||||
public IIOHelper IOHelper { get; }
|
||||
public IMainDom MainDom { get; }
|
||||
public UriUtility UriUtility { get; }
|
||||
public UriUtility UriUtility
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_uriUtility == null)
|
||||
_uriUtility = new UriUtility(GetHostingEnvironment());
|
||||
return _uriUtility;
|
||||
}
|
||||
}
|
||||
|
||||
public SettingsForTests SettingsForTests { get; }
|
||||
public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings();
|
||||
|
||||
@@ -115,10 +124,7 @@ namespace Umbraco.Tests.Common
|
||||
return relativePath.Replace("~/", CurrentAssemblyDirectory + "/");
|
||||
}
|
||||
|
||||
public IUmbracoVersion GetUmbracoVersion()
|
||||
{
|
||||
return new UmbracoVersion(GetConfigs().Global());
|
||||
}
|
||||
public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(GetConfigs().Global());
|
||||
|
||||
public IRegister GetRegister()
|
||||
{
|
||||
|
||||
77
src/Umbraco.Tests.Integration/ContainerTests.cs
Normal file
77
src/Umbraco.Tests.Integration/ContainerTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using LightInject;
|
||||
using LightInject.Microsoft.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing.LightInject;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Tests.Common;
|
||||
using Umbraco.Tests.Integration.Implementations;
|
||||
|
||||
namespace Umbraco.Tests.Integration
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class ContainerTests
|
||||
{
|
||||
[Test]
|
||||
public void CrossWire()
|
||||
{
|
||||
// MSDI
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<Foo>();
|
||||
var msdiServiceProvider = services.BuildServiceProvider();
|
||||
|
||||
// LightInject / Umbraco
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services
|
||||
|
||||
// Dependencies needed for creating composition/register essentials
|
||||
var testHelper = new TestHelper();
|
||||
var runtimeState = Mock.Of<IRuntimeState>();
|
||||
var umbracoDatabaseFactory = Mock.Of<IUmbracoDatabaseFactory>();
|
||||
var dbProviderFactoryCreator = Mock.Of<IDbProviderFactoryCreator>();
|
||||
var typeLoader = testHelper.GetMockedTypeLoader();
|
||||
|
||||
// Register in the container
|
||||
var composition = new Composition(umbracoContainer, typeLoader,
|
||||
testHelper.Logger, runtimeState, testHelper.GetConfigs(), testHelper.IOHelper, testHelper.AppCaches);
|
||||
composition.RegisterEssentials(testHelper.Logger, testHelper.Profiler, testHelper.Logger, testHelper.MainDom,
|
||||
testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(),
|
||||
testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator);
|
||||
|
||||
// Cross wire - this would be called by the Host Builder at the very end of ConfigureServices
|
||||
var lightInjectServiceProvider = serviceProviderFactory.CreateServiceProvider(umbracoContainer.Container);
|
||||
|
||||
// From MSDI
|
||||
var foo1 = msdiServiceProvider.GetService<Foo>();
|
||||
var foo2 = lightInjectServiceProvider.GetService<Foo>();
|
||||
var foo3 = umbracoContainer.GetInstance<Foo>();
|
||||
|
||||
Assert.IsNotNull(foo1);
|
||||
Assert.IsNotNull(foo2);
|
||||
Assert.IsNotNull(foo3);
|
||||
|
||||
// These are not the same because cross wiring means copying the container, not falling back to a container
|
||||
Assert.AreNotSame(foo1, foo2);
|
||||
// These are the same because the umbraco container wraps the light inject container
|
||||
Assert.AreSame(foo2, foo3);
|
||||
|
||||
Assertions.AssertContainer(umbracoContainer.Container);
|
||||
}
|
||||
|
||||
private class Foo
|
||||
{
|
||||
public Foo()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Data.Common;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Tests.Integration.Implementations
|
||||
{
|
||||
public class TestDbProviderFactoryCreator : IDbProviderFactoryCreator
|
||||
{
|
||||
public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void CreateDatabase()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public DbProviderFactory CreateFactory()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public DbProviderFactory CreateFactory(string providerName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
Normal file
80
src/Umbraco.Tests.Integration/Implementations/TestHelper.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using System.Net;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Diagnostics;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Tests.Common;
|
||||
using Umbraco.Web.BackOffice;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment;
|
||||
|
||||
namespace Umbraco.Tests.Integration.Implementations
|
||||
{
|
||||
|
||||
public class TestHelper : TestHelperBase
|
||||
{
|
||||
private IBackOfficeInfo _backOfficeInfo;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly IIpResolver _ipResolver;
|
||||
private readonly IWebHostEnvironment _hostEnvironment;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public TestHelper() : base(typeof(TestHelper).Assembly)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Connection.RemoteIpAddress = IPAddress.Parse("127.0.0.1");
|
||||
_httpContextAccessor = Mock.Of<IHttpContextAccessor>(x => x.HttpContext == httpContext);
|
||||
_ipResolver = new AspNetIpResolver(_httpContextAccessor);
|
||||
|
||||
_hostEnvironment = Mock.Of<IWebHostEnvironment>(x =>
|
||||
x.ApplicationName == "UmbracoIntegrationTests"
|
||||
&& x.ContentRootPath == CurrentAssemblyDirectory
|
||||
&& x.WebRootPath == CurrentAssemblyDirectory); // same folder for now?
|
||||
|
||||
_hostingEnvironment = new AspNetCoreHostingEnvironment(
|
||||
SettingsForTests.GetDefaultHostingSettings(),
|
||||
_hostEnvironment,
|
||||
_httpContextAccessor,
|
||||
Mock.Of<IHostApplicationLifetime>());
|
||||
|
||||
Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler);
|
||||
}
|
||||
|
||||
public IUmbracoBootPermissionChecker UmbracoBootPermissionChecker { get; } = new TestUmbracoBootPermissionChecker();
|
||||
|
||||
public AppCaches AppCaches { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(type => NoAppCache.Instance));
|
||||
|
||||
public IProfilingLogger Logger { get; private set; }
|
||||
|
||||
public IProfiler Profiler { get; } = new VoidProfiler();
|
||||
|
||||
public IHttpContextAccessor GetHttpContextAccessor() => _httpContextAccessor;
|
||||
|
||||
public IWebHostEnvironment GetWebHostEnvironment() => _hostEnvironment;
|
||||
|
||||
public override IDbProviderFactoryCreator DbProviderFactoryCreator => new TestDbProviderFactoryCreator();
|
||||
|
||||
public override IBulkSqlInsertProvider BulkSqlInsertProvider => new SqlServerBulkSqlInsertProvider();
|
||||
|
||||
public override IMarchal Marchal { get; } = new AspNetCoreMarchal();
|
||||
|
||||
public override IBackOfficeInfo GetBackOfficeInfo()
|
||||
{
|
||||
if (_backOfficeInfo == null)
|
||||
_backOfficeInfo = new AspNetCoreBackOfficeInfo(SettingsForTests.GetDefaultGlobalSettings(GetUmbracoVersion()));
|
||||
return _backOfficeInfo;
|
||||
}
|
||||
|
||||
public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment;
|
||||
|
||||
public override IIpResolver GetIpResolver() => _ipResolver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Core.Runtime;
|
||||
|
||||
namespace Umbraco.Tests.Integration.Implementations
|
||||
{
|
||||
public class TestUmbracoBootPermissionChecker : IUmbracoBootPermissionChecker
|
||||
{
|
||||
public void ThrowIfNotPermissions()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/Umbraco.Tests.Integration/RuntimeTests.cs
Normal file
128
src/Umbraco.Tests.Integration/RuntimeTests.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using LightInject;
|
||||
using LightInject.Microsoft.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Tests.Common;
|
||||
using Umbraco.Tests.Integration.Implementations;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
|
||||
namespace Umbraco.Tests.Integration
|
||||
{
|
||||
[TestFixture]
|
||||
public class RuntimeTests
|
||||
{
|
||||
[Test]
|
||||
public void BootCoreRuntime()
|
||||
{
|
||||
// LightInject / Umbraco
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
|
||||
// Create the core runtime
|
||||
var testHelper = new TestHelper();
|
||||
var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(),
|
||||
testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker,
|
||||
testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator,
|
||||
testHelper.MainDom, testHelper.GetTypeFinder());
|
||||
|
||||
// boot it!
|
||||
var factory = coreRuntime.Boot(umbracoContainer);
|
||||
|
||||
Assert.IsTrue(coreRuntime.MainDom.IsMainDom);
|
||||
Assert.IsNull(coreRuntime.State.BootFailedException);
|
||||
Assert.AreEqual(RuntimeLevel.Install, coreRuntime.State.Level);
|
||||
Assert.IsTrue(MyComposer.IsComposed);
|
||||
Assert.IsTrue(MyComponent.IsInit);
|
||||
Assert.IsFalse(MyComponent.IsTerminated);
|
||||
|
||||
Assertions.AssertContainer(umbracoContainer.Container, reportOnly: true); // TODO Change that to false eventually when we clean up the container
|
||||
|
||||
coreRuntime.Terminate();
|
||||
|
||||
Assert.IsTrue(MyComponent.IsTerminated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddUmbracoCore()
|
||||
{
|
||||
var testHelper = new TestHelper();
|
||||
|
||||
// MSDI
|
||||
var services = new ServiceCollection();
|
||||
// These services are required
|
||||
services.AddSingleton<IHttpContextAccessor>(x => testHelper.GetHttpContextAccessor());
|
||||
services.AddSingleton<IWebHostEnvironment>(x => testHelper.GetWebHostEnvironment());
|
||||
services.AddSingleton<IHostApplicationLifetime>(x => Mock.Of<IHostApplicationLifetime>());
|
||||
|
||||
// LightInject / Umbraco
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
|
||||
// Some IConfiguration must exist in the container first
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddEnvironmentVariables();
|
||||
services.AddSingleton<IConfiguration>(x => configurationBuilder.Build());
|
||||
|
||||
// Add it!
|
||||
services.AddUmbracoConfiguration();
|
||||
services.AddUmbracoCore(umbracoContainer, GetType().Assembly);
|
||||
|
||||
// assert results
|
||||
var runtimeState = umbracoContainer.GetInstance<IRuntimeState>();
|
||||
var mainDom = umbracoContainer.GetInstance<IMainDom>();
|
||||
|
||||
Assert.IsTrue(mainDom.IsMainDom);
|
||||
Assert.IsNull(runtimeState.BootFailedException);
|
||||
Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level);
|
||||
Assert.IsTrue(MyComposer.IsComposed);
|
||||
}
|
||||
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Install)]
|
||||
public class MyComposer : IUserComposer
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
composition.Components().Append<MyComponent>();
|
||||
IsComposed = true;
|
||||
}
|
||||
|
||||
public static bool IsComposed { get; private set; }
|
||||
}
|
||||
|
||||
public class MyComponent : IComponent
|
||||
{
|
||||
public static bool IsInit { get; private set; }
|
||||
public static bool IsTerminated { get; private set; }
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MyComponent(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
IsInit = true;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
IsTerminated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LightInject.Microsoft.DependencyInjection" Version="3.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.13.1" />
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Tests.Common\Umbraco.Tests.Common.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Tests.Routing
|
||||
public class TestRuntime : WebRuntime
|
||||
{
|
||||
public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
|
||||
: base(configs, umbracoVersion, ioHelper, Mock.Of<ILogger>(), Mock.Of<IProfiler>(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetRequestCache(), new AspNetUmbracoBootPermissionChecker())
|
||||
: base(configs, umbracoVersion, ioHelper, Mock.Of<ILogger>(), Mock.Of<IProfiler>(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), TestHelper.GetRequestCache(), new AspNetUmbracoBootPermissionChecker())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -121,15 +121,11 @@ namespace Umbraco.Tests.Runtimes
|
||||
public class TestRuntime : CoreRuntime
|
||||
{
|
||||
public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
|
||||
:base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom)
|
||||
:base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// override because we cannot use Assembly.GetEntryAssembly in Nunit tests since that is always null
|
||||
protected override ITypeFinder GetTypeFinder()
|
||||
=> new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
|
||||
|
||||
// must override the database factory
|
||||
// else BootFailedException because U cannot connect to the configured db
|
||||
protected internal override IUmbracoDatabaseFactory GetDatabaseFactory()
|
||||
@@ -181,7 +177,6 @@ namespace Umbraco.Tests.Runtimes
|
||||
|
||||
public override void Terminate()
|
||||
{
|
||||
((IRegisteredObject) _mainDom).Stop(false);
|
||||
base.Terminate();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ using Umbraco.Core.Runtime;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Tests.Composing;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Cache;
|
||||
@@ -36,6 +35,7 @@ using Umbraco.Web.Runtime;
|
||||
using File = System.IO.File;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
using Umbraco.Tests.Common;
|
||||
using Umbraco.Tests.Common.Composing;
|
||||
|
||||
namespace Umbraco.Tests.Runtimes
|
||||
{
|
||||
@@ -64,8 +64,8 @@ namespace Umbraco.Tests.Runtimes
|
||||
var appCaches = AppCaches.Disabled;
|
||||
var globalSettings = TestHelper.GetConfigs().Global();
|
||||
var connectionStrings = TestHelper.GetConfigs().ConnectionStrings();
|
||||
var typeFinder = TestHelper.GetTypeFinder();
|
||||
var databaseFactory = new UmbracoDatabaseFactory(logger,globalSettings, connectionStrings, new Lazy<IMapperCollection>(() => factory.GetInstance<IMapperCollection>()), TestHelper.DbProviderFactoryCreator);
|
||||
var typeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly));
|
||||
var ioHelper = TestHelper.IOHelper;
|
||||
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
|
||||
var typeLoader = new TypeLoader(ioHelper, typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger);
|
||||
@@ -75,6 +75,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
var runtimeState = new RuntimeState(logger, null, new Lazy<IMainDom>(() => mainDom), new Lazy<IServerRegistrar>(() => factory.GetInstance<IServerRegistrar>()), umbracoVersion, hostingEnvironment, backOfficeInfo);
|
||||
var configs = TestHelper.GetConfigs();
|
||||
var variationContextAccessor = TestHelper.VariationContextAccessor;
|
||||
|
||||
|
||||
// create the register and the composition
|
||||
var register = TestHelper.GetRegister();
|
||||
@@ -82,7 +83,8 @@ namespace Umbraco.Tests.Runtimes
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator);
|
||||
|
||||
// create the core runtime and have it compose itself
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom);coreRuntime.Compose(composition);
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder);
|
||||
coreRuntime.Compose(composition);
|
||||
|
||||
// determine actual runtime level
|
||||
runtimeState.DetermineRuntimeLevel(databaseFactory, logger);
|
||||
@@ -276,7 +278,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator);
|
||||
|
||||
// create the core runtime and have it compose itself
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom);
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder);
|
||||
coreRuntime.Compose(composition);
|
||||
|
||||
// get the components
|
||||
@@ -315,107 +317,14 @@ namespace Umbraco.Tests.Runtimes
|
||||
foreach (var result in resultGroup)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.Write(ToText(result));
|
||||
Console.Write(result.ToText());
|
||||
}
|
||||
|
||||
Assert.AreEqual(0, results.Count);
|
||||
}
|
||||
|
||||
private static string ToText(ValidationResult result)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
|
||||
|
||||
text.AppendLine($"{result.Severity}: {WordWrap(result.Message, 120)}");
|
||||
var target = result.ValidationTarget;
|
||||
text.Append("\tsvce: ");
|
||||
text.Append(target.ServiceName);
|
||||
text.Append(target.DeclaringService.ServiceType);
|
||||
if (!target.DeclaringService.ServiceName.IsNullOrWhiteSpace())
|
||||
{
|
||||
text.Append(" '");
|
||||
text.Append(target.DeclaringService.ServiceName);
|
||||
text.Append("'");
|
||||
}
|
||||
|
||||
text.Append(" (");
|
||||
if (target.DeclaringService.Lifetime == null)
|
||||
text.Append("Transient");
|
||||
else
|
||||
text.Append(target.DeclaringService.Lifetime.ToString().TrimStart("LightInject.").TrimEnd("Lifetime"));
|
||||
text.AppendLine(")");
|
||||
text.Append("\timpl: ");
|
||||
text.Append(target.DeclaringService.ImplementingType);
|
||||
text.AppendLine();
|
||||
text.Append("\tparm: ");
|
||||
text.Append(target.Parameter);
|
||||
text.AppendLine();
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static string WordWrap(string text, int width)
|
||||
{
|
||||
int pos, next;
|
||||
var sb = new StringBuilder();
|
||||
var nl = Environment.NewLine;
|
||||
|
||||
// Lucidity check
|
||||
if (width < 1)
|
||||
return text;
|
||||
|
||||
// Parse each line of text
|
||||
for (pos = 0; pos < text.Length; pos = next)
|
||||
{
|
||||
// Find end of line
|
||||
var eol = text.IndexOf(nl, pos, StringComparison.Ordinal);
|
||||
|
||||
if (eol == -1)
|
||||
next = eol = text.Length;
|
||||
else
|
||||
next = eol + nl.Length;
|
||||
|
||||
// Copy this line of text, breaking into smaller lines as needed
|
||||
if (eol > pos)
|
||||
{
|
||||
do
|
||||
{
|
||||
var len = eol - pos;
|
||||
|
||||
if (len > width)
|
||||
len = BreakLine(text, pos, width);
|
||||
|
||||
if (pos > 0)
|
||||
sb.Append("\t\t");
|
||||
sb.Append(text, pos, len);
|
||||
sb.Append(nl);
|
||||
|
||||
// Trim whitespace following break
|
||||
pos += len;
|
||||
|
||||
while (pos < eol && char.IsWhiteSpace(text[pos]))
|
||||
pos++;
|
||||
|
||||
} while (eol > pos);
|
||||
}
|
||||
else sb.Append(nl); // Empty line
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static int BreakLine(string text, int pos, int max)
|
||||
{
|
||||
// Find last whitespace in line
|
||||
var i = max - 1;
|
||||
while (i >= 0 && !char.IsWhiteSpace(text[pos + i]))
|
||||
i--;
|
||||
if (i < 0)
|
||||
return max; // No whitespace found; break at maximum length
|
||||
// Find start of whitespace
|
||||
while (i >= 0 && char.IsWhiteSpace(text[pos + i]))
|
||||
i--;
|
||||
// Return length of text before whitespace
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Umbraco.Tests.TestHelpers
|
||||
protected override void Compose()
|
||||
{
|
||||
base.Compose();
|
||||
base.Compose();
|
||||
|
||||
Composition.RegisterUnique<IPublishedValueFallback, PublishedValueFallback>();
|
||||
Composition.RegisterUnique<IProfilingLogger, ProfilingLogger>();
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace Umbraco.Tests.TestHelpers
|
||||
private static TestHelperInternal _testHelperInternal = new TestHelperInternal();
|
||||
private class TestHelperInternal : TestHelperBase
|
||||
{
|
||||
public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = new UmbracoDbProviderFactoryCreator(Constants.DbProviderNames.SqlCe);
|
||||
|
||||
public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = new SqlCeBulkSqlInsertProvider();
|
||||
|
||||
@@ -120,7 +120,6 @@
|
||||
<Compile Include="Clr\ReflectionUtilitiesTests.cs" />
|
||||
<Compile Include="Collections\OrderedHashSetTests.cs" />
|
||||
<Compile Include="Composing\CompositionTests.cs" />
|
||||
<Compile Include="Composing\LightInjectValidation.cs" />
|
||||
<Compile Include="Composing\ContainerConformingTests.cs" />
|
||||
<Compile Include="Configurations\GlobalSettingsTests.cs" />
|
||||
<Compile Include="CoreThings\CallContextTests.cs" />
|
||||
@@ -210,7 +209,6 @@
|
||||
<Compile Include="Services\CachedDataTypeServiceTests.cs" />
|
||||
<Compile Include="Services\ConsentServiceTests.cs" />
|
||||
<Compile Include="Services\SectionServiceTests.cs" />
|
||||
<Compile Include="TestHelpers\ConsoleLogger.cs" />
|
||||
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingExtensions.cs" />
|
||||
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingMiddleware.cs" />
|
||||
<Compile Include="TestHelpers\ControllerTesting\SpecificAssemblyResolver.cs" />
|
||||
|
||||
@@ -84,9 +84,10 @@ namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: This may need to take into account ~/ paths which means the ApplicationVirtualPath and is this the content root or web root?
|
||||
public string MapPath(string path) => Path.Combine(_webHostEnvironment.WebRootPath, path);
|
||||
|
||||
// TODO: Need to take into account 'root' here
|
||||
public string ToAbsolute(string virtualPath, string root)
|
||||
{
|
||||
if (Uri.TryCreate(virtualPath, UriKind.Absolute, out _))
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
{
|
||||
internal class AspNetIpResolver : IIpResolver
|
||||
public class AspNetIpResolver : IIpResolver
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Umbraco.Net;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
@@ -12,6 +13,18 @@ namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string SessionId => _httpContextAccessor?.HttpContext.Session?.Id;
|
||||
|
||||
public string SessionId
|
||||
{
|
||||
get
|
||||
{
|
||||
var httpContext = _httpContextAccessor?.HttpContext;
|
||||
// If session isn't enabled this will throw an exception so we check
|
||||
var sessionFeature = httpContext?.Features.Get<ISessionFeature>();
|
||||
return sessionFeature != null
|
||||
? httpContext?.Session?.Id
|
||||
: "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@@ -7,20 +10,29 @@ using Umbraco.Composing;
|
||||
using Umbraco.Configuration;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Logging.Serilog;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Runtime;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
{
|
||||
|
||||
|
||||
public static class UmbracoBackOfficeServiceCollectionExtensions
|
||||
{
|
||||
|
||||
public static IServiceCollection AddUmbracoConfiguration(this IServiceCollection services)
|
||||
{
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var configuration = serviceProvider.GetService<IConfiguration>();
|
||||
if (configuration == null)
|
||||
throw new InvalidOperationException($"Could not resolve {typeof(IConfiguration)} from the container");
|
||||
|
||||
var configsFactory = new AspNetCoreConfigsFactory(configuration);
|
||||
|
||||
var configs = configsFactory.Create();
|
||||
@@ -30,44 +42,102 @@ namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddUmbracoBackOffice(this IServiceCollection services)
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Umbraco Back Core requirements
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Must be called after all services are added to the application because we are cross-wiring the container (currently)
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddUmbracoCore(this IServiceCollection services)
|
||||
{
|
||||
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;
|
||||
|
||||
return services.AddUmbracoCore(umbContainer, Assembly.GetEntryAssembly());
|
||||
}
|
||||
|
||||
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IRegister umbContainer, Assembly entryAssembly)
|
||||
{
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
CreateCompositionRoot(services);
|
||||
|
||||
var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
|
||||
var webHostEnvironment = serviceProvider.GetService<IWebHostEnvironment>();
|
||||
var hostApplicationLifetime = serviceProvider.GetService<IHostApplicationLifetime>();
|
||||
// TODO: Get rid of this 'Current' requirement
|
||||
var globalSettings = Current.Configs.Global();
|
||||
var umbracoVersion = new UmbracoVersion(globalSettings);
|
||||
|
||||
var configs = serviceProvider.GetService<Configs>();
|
||||
// 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.
|
||||
var typeFinder = new TypeFinder(Current.Logger, new DefaultUmbracoAssemblyProvider(entryAssembly));
|
||||
|
||||
services.CreateCompositionRoot(
|
||||
httpContextAccessor,
|
||||
webHostEnvironment,
|
||||
hostApplicationLifetime,
|
||||
configs);
|
||||
var coreRuntime = GetCoreRuntime(
|
||||
Current.Configs,
|
||||
umbracoVersion,
|
||||
Current.IOHelper,
|
||||
Current.Logger,
|
||||
Current.Profiler,
|
||||
Current.HostingEnvironment,
|
||||
Current.BackOfficeInfo,
|
||||
typeFinder);
|
||||
|
||||
var factory = coreRuntime.Boot(umbContainer);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
public static IServiceCollection CreateCompositionRoot(
|
||||
this IServiceCollection services,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
IHostApplicationLifetime hostApplicationLifetime,
|
||||
Configs configs)
|
||||
private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger,
|
||||
IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
|
||||
ITypeFinder typeFinder)
|
||||
{
|
||||
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
|
||||
var globalSettings = configs.Global();
|
||||
var connStrings = configs.ConnectionStrings();
|
||||
var appSettingMainDomLock = globalSettings.MainDomLock;
|
||||
var mainDomLock = appSettingMainDomLock == "SqlMainDomLock"
|
||||
? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connStrings, dbProviderFactoryCreator)
|
||||
: new MainDomSemaphoreLock(logger, hostingEnvironment);
|
||||
|
||||
var mainDom = new MainDom(logger, hostingEnvironment, mainDomLock);
|
||||
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetCoreBootPermissionsChecker(),
|
||||
hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder);
|
||||
|
||||
return coreRuntime;
|
||||
}
|
||||
|
||||
private static void CreateCompositionRoot(IServiceCollection services)
|
||||
{
|
||||
// TODO: This isn't the best to have to resolve the services now but to avoid this will
|
||||
// require quite a lot of re-work.
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
|
||||
var webHostEnvironment = serviceProvider.GetRequiredService<IWebHostEnvironment>();
|
||||
var hostApplicationLifetime = serviceProvider.GetRequiredService<IHostApplicationLifetime>();
|
||||
|
||||
var configs = serviceProvider.GetService<Configs>();
|
||||
if (configs == null)
|
||||
throw new InvalidOperationException($"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}");
|
||||
|
||||
var hostingSettings = configs.Hosting();
|
||||
var coreDebug = configs.CoreDebug();
|
||||
var globalSettings = configs.Global();
|
||||
|
||||
var hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment,
|
||||
httpContextAccessor, hostApplicationLifetime);
|
||||
var hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment, httpContextAccessor, hostApplicationLifetime);
|
||||
var ioHelper = new IOHelper(hostingEnvironment, globalSettings);
|
||||
var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment,
|
||||
new AspNetCoreSessionIdResolver(httpContextAccessor),
|
||||
// need to build a new service provider since the one already resolved above doesn't have the IRequestCache yet
|
||||
() => services.BuildServiceProvider().GetService<IRequestCache>(), coreDebug, ioHelper,
|
||||
new AspNetCoreMarchal());
|
||||
|
||||
@@ -75,8 +145,14 @@ namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
var profiler = new LogProfiler(logger);
|
||||
|
||||
Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
|
||||
}
|
||||
|
||||
return services;
|
||||
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
|
||||
{
|
||||
public void ThrowIfNotPermissions()
|
||||
{
|
||||
// nothing to check
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Configuration\Umbraco.Configuration.csproj" />
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.UI.BackOffice
|
||||
{
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
|
||||
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
|
||||
.UseUmbraco();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
|
||||
services.AddUmbracoConfiguration();
|
||||
services.AddUmbracoRequest();
|
||||
services.AddUmbracoCore();
|
||||
services.AddUmbracoWebsite();
|
||||
services.AddUmbracoBackOffice();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Web
|
||||
|
||||
var requestCache = new HttpRequestAppCache(() => HttpContext.Current?.Items);
|
||||
var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker();
|
||||
return new WebRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, requestCache, umbracoBootPermissionChecker);
|
||||
return new WebRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, GetTypeFinder(), requestCache, umbracoBootPermissionChecker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,10 @@ namespace Umbraco.Web
|
||||
public abstract class UmbracoApplicationBase : HttpApplication
|
||||
{
|
||||
private IRuntime _runtime;
|
||||
|
||||
private IFactory _factory;
|
||||
|
||||
protected UmbracoApplicationBase()
|
||||
{
|
||||
|
||||
if (!Umbraco.Composing.Current.IsInitialized)
|
||||
{
|
||||
var configFactory = new ConfigsFactory();
|
||||
@@ -46,8 +44,8 @@ namespace Umbraco.Web
|
||||
var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, logger, configFactory.WebRoutingSettings);
|
||||
var profiler = GetWebProfiler(hostingEnvironment);
|
||||
Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private IProfiler GetWebProfiler(IHostingEnvironment hostingEnvironment)
|
||||
@@ -67,13 +65,36 @@ namespace Umbraco.Web
|
||||
}
|
||||
|
||||
protected UmbracoApplicationBase(ILogger logger, Configs configs, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
|
||||
{
|
||||
{
|
||||
if (!Umbraco.Composing.Current.IsInitialized)
|
||||
{
|
||||
Logger = logger;
|
||||
Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler);
|
||||
}
|
||||
}
|
||||
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITypeFinder"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual ITypeFinder GetTypeFinder()
|
||||
// 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.
|
||||
=> new TypeFinder(Logger, new DefaultUmbracoAssemblyProvider(
|
||||
// GetEntryAssembly was actually an exposed API by request of the aspnetcore team which works in aspnet core because a website
|
||||
// in that case is essentially an exe. However in netframework there is no entry assembly, things don't really work that way since
|
||||
// the process that is running the site is iisexpress, so this returns null. The best we can do is fallback to GetExecutingAssembly()
|
||||
// which will just return Umbraco.Infrastructure (currently with netframework) and for our purposes that is OK.
|
||||
// If you are curious... There is really no way to get the entry assembly in netframework without the hosting website having it's own
|
||||
// code compiled for the global.asax which is the entry point. Because the default global.asax for umbraco websites is just a file inheriting
|
||||
// from Umbraco.Web.UmbracoApplication, the global.asax file gets dynamically compiled into a DLL in the dynamic folder (we can get an instance
|
||||
// of that, but this doesn't really help us) but the actually entry execution is still Umbraco.Web. So that is the 'highest' level entry point
|
||||
// assembly we can get and we can only get that if we put this code into the WebRuntime since the executing assembly is the 'current' one.
|
||||
// For this purpose, it doesn't matter if it's Umbraco.Web or Umbraco.Infrastructure since all assemblies are in that same path and we are
|
||||
// getting rid of netframework.
|
||||
Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()));
|
||||
|
||||
/// <summary>
|
||||
/// Gets a runtime.
|
||||
|
||||
@@ -121,6 +121,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.UI.NetCore", "U
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Website", "Umbraco.Web.Website\Umbraco.Web.Website.csproj", "{5A246D54-3109-4D2B-BE7D-FC0787D126AE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.Integration", "Umbraco.Tests.Integration\Umbraco.Tests.Integration.csproj", "{D6319409-777A-4BD0-93ED-B2DFD805B32C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Tests.Common", "Umbraco.Tests.Common\Umbraco.Tests.Common.csproj", "{A499779C-1B3B-48A8-B551-458E582E6E96}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.Common", "Umbraco.Web.Common\Umbraco.Web.Common.csproj", "{839D3048-9718-4907-BDE0-7CD63D364383}"
|
||||
@@ -193,6 +195,10 @@ Global
|
||||
{5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6319409-777A-4BD0-93ED-B2DFD805B32C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6319409-777A-4BD0-93ED-B2DFD805B32C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6319409-777A-4BD0-93ED-B2DFD805B32C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6319409-777A-4BD0-93ED-B2DFD805B32C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -214,6 +220,7 @@ Global
|
||||
{3A33ADC9-C6C0-4DB1-A613-A9AF0210DF3D} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
|
||||
{C7311C00-2184-409B-B506-52A5FAEA8736} = {FD962632-184C-4005-A5F3-E705D92FC645}
|
||||
{FB5676ED-7A69-492C-B802-E7B24144C0FC} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
|
||||
{D6319409-777A-4BD0-93ED-B2DFD805B32C} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
|
||||
{A499779C-1B3B-48A8-B551-458E582E6E96} = {B5BD12C1-A454-435E-8A46-FF4A364C0382}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
||||
Reference in New Issue
Block a user