Introduced GenericDictionaryRequestAppCache, to use the HttpContext.Items from .NET Core
This commit is contained in:
190
src/Umbraco.Core/Cache/GenericDictionaryRequestAppCache.cs
Normal file
190
src/Umbraco.Core/Cache/GenericDictionaryRequestAppCache.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a fast <see cref="IAppCache"/> on top of HttpContext.Items.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If no current HttpContext items can be found (no current HttpContext,
|
||||
/// or no Items...) then this cache acts as a pass-through and does not cache
|
||||
/// anything.</para>
|
||||
/// </remarks>
|
||||
public class GenericDictionaryRequestAppCache : FastDictionaryAppCacheBase, IRequestCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpRequestAppCache"/> class with a context, for unit tests!
|
||||
/// </summary>
|
||||
public GenericDictionaryRequestAppCache(Func<IDictionary<object, object>> requestItems) : base()
|
||||
{
|
||||
ContextItems = requestItems;
|
||||
}
|
||||
|
||||
private Func<IDictionary<object, object>> ContextItems { get; }
|
||||
|
||||
public bool IsAvailable => TryGetContextItems(out _);
|
||||
|
||||
private bool TryGetContextItems(out IDictionary<object, object> items)
|
||||
{
|
||||
items = ContextItems?.Invoke();
|
||||
return items != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Get(string key, Func<object> factory)
|
||||
{
|
||||
//no place to cache so just return the callback result
|
||||
if (!TryGetContextItems(out var items)) return factory();
|
||||
|
||||
key = GetCacheKey(key);
|
||||
|
||||
Lazy<object> result;
|
||||
|
||||
try
|
||||
{
|
||||
EnterWriteLock();
|
||||
result = items[key] as Lazy<object>; // null if key not found
|
||||
|
||||
// cannot create value within the lock, so if result.IsValueCreated is false, just
|
||||
// do nothing here - means that if creation throws, a race condition could cause
|
||||
// more than one thread to reach the return statement below and throw - accepted.
|
||||
|
||||
if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = SafeLazy.GetSafeLazy(factory);
|
||||
items[key] = result;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitWriteLock();
|
||||
}
|
||||
|
||||
// using GetSafeLazy and GetSafeLazyValue ensures that we don't cache
|
||||
// exceptions (but try again and again) and silently eat them - however at
|
||||
// some point we have to report them - so need to re-throw here
|
||||
|
||||
// this does not throw anymore
|
||||
//return result.Value;
|
||||
|
||||
var value = result.Value; // will not throw (safe lazy)
|
||||
if (value is SafeLazy.ExceptionHolder eh) eh.Exception.Throw(); // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool Set(string key, object value)
|
||||
{
|
||||
//no place to cache so just return the callback result
|
||||
if (!TryGetContextItems(out var items)) return false;
|
||||
key = GetCacheKey(key);
|
||||
try
|
||||
{
|
||||
|
||||
EnterWriteLock();
|
||||
items[key] = SafeLazy.GetSafeLazy(() => value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitWriteLock();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
//no place to cache so just return the callback result
|
||||
if (!TryGetContextItems(out var items)) return false;
|
||||
key = GetCacheKey(key);
|
||||
try
|
||||
{
|
||||
|
||||
EnterWriteLock();
|
||||
items.Remove(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ExitWriteLock();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Entries
|
||||
|
||||
protected override IEnumerable<DictionaryEntry> GetDictionaryEntries()
|
||||
{
|
||||
const string prefix = CacheItemPrefix + "-";
|
||||
|
||||
if (!TryGetContextItems(out var items)) return Enumerable.Empty<DictionaryEntry>();
|
||||
|
||||
return items.Cast<DictionaryEntry>()
|
||||
.Where(x => x.Key is string s && s.StartsWith(prefix));
|
||||
}
|
||||
|
||||
protected override void RemoveEntry(string key)
|
||||
{
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
items.Remove(key);
|
||||
}
|
||||
|
||||
protected override object GetEntry(string key)
|
||||
{
|
||||
return !TryGetContextItems(out var items) ? null : items[key];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lock
|
||||
|
||||
private const string ContextItemsLockKey = "Umbraco.Core.Cache.HttpRequestCache::LockEntered";
|
||||
|
||||
protected override void EnterReadLock() => EnterWriteLock();
|
||||
|
||||
protected override void EnterWriteLock()
|
||||
{
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
// note: cannot keep 'entered' as a class variable here,
|
||||
// since there is one per request - so storing it within
|
||||
// ContextItems - which is locked, so this should be safe
|
||||
|
||||
var entered = false;
|
||||
Monitor.Enter(items, ref entered);
|
||||
items[ContextItemsLockKey] = entered;
|
||||
}
|
||||
|
||||
protected override void ExitReadLock() => ExitWriteLock();
|
||||
|
||||
protected override void ExitWriteLock()
|
||||
{
|
||||
if (!TryGetContextItems(out var items)) return;
|
||||
|
||||
var entered = (bool?)items[ContextItemsLockKey] ?? false;
|
||||
if (entered)
|
||||
Monitor.Exit(items);
|
||||
items.Remove(ContextItemsLockKey);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
if (!TryGetContextItems(out var items))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
yield return new KeyValuePair<string, object>(item.Key.ToString(), item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace Umbraco.Core.Runtime
|
||||
private IFactory _factory;
|
||||
private readonly RuntimeState _state;
|
||||
private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker;
|
||||
private readonly IRequestCache _requestCache;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IConnectionStrings _connectionStrings;
|
||||
|
||||
@@ -39,7 +40,8 @@ namespace Umbraco.Core.Runtime
|
||||
IBackOfficeInfo backOfficeInfo,
|
||||
IDbProviderFactoryCreator dbProviderFactoryCreator,
|
||||
IMainDom mainDom,
|
||||
ITypeFinder typeFinder)
|
||||
ITypeFinder typeFinder,
|
||||
IRequestCache requestCache)
|
||||
{
|
||||
IOHelper = ioHelper;
|
||||
Configs = configs;
|
||||
@@ -50,6 +52,7 @@ namespace Umbraco.Core.Runtime
|
||||
DbProviderFactoryCreator = dbProviderFactoryCreator;
|
||||
|
||||
_umbracoBootPermissionChecker = umbracoBootPermissionChecker;
|
||||
_requestCache = requestCache;
|
||||
|
||||
Logger = logger;
|
||||
MainDom = mainDom;
|
||||
@@ -110,6 +113,7 @@ namespace Umbraco.Core.Runtime
|
||||
{
|
||||
if (register is null) throw new ArgumentNullException(nameof(register));
|
||||
|
||||
|
||||
// create and register the essential services
|
||||
// ie the bare minimum required to boot
|
||||
|
||||
@@ -129,12 +133,25 @@ namespace Umbraco.Core.Runtime
|
||||
"Booted.",
|
||||
"Boot failed."))
|
||||
{
|
||||
Logger.Info<CoreRuntime>("Booting Core");
|
||||
|
||||
Logger.Info<CoreRuntime>("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
|
||||
HostingEnvironment?.SiteName,
|
||||
HostingEnvironment?.ApplicationId,
|
||||
HostingEnvironment?.ApplicationPhysicalPath,
|
||||
NetworkHelper.MachineName);
|
||||
Logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
|
||||
|
||||
// application environment
|
||||
ConfigureUnhandledException();
|
||||
return _factory = Configure(register, timer);
|
||||
_factory = Configure(register, timer);
|
||||
|
||||
// now (and only now) is the time to switch over to perWebRequest scopes.
|
||||
// up until that point we may not have a request, and scoped services would
|
||||
// fail to resolve - but we run Initialize within a factory scope - and then,
|
||||
// here, we switch the factory to bind scopes to requests
|
||||
_factory.EnablePerWebRequestScope();
|
||||
|
||||
return _factory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +168,7 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
|
||||
// run handlers
|
||||
RuntimeOptions.DoRuntimeBoot(ProfilingLogger);
|
||||
@@ -350,7 +367,7 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
return new AppCaches(
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache()),
|
||||
NoAppCache.Instance,
|
||||
_requestCache,
|
||||
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Runtime;
|
||||
|
||||
namespace Umbraco.Web.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Web Umbraco runtime.
|
||||
/// </summary>
|
||||
/// <remarks>On top of CoreRuntime, handles all of the web-related runtime aspects of Umbraco.</remarks>
|
||||
public class WebRuntime : CoreRuntime
|
||||
{
|
||||
private readonly IRequestCache _requestCache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebRuntime"/> class.
|
||||
/// </summary>
|
||||
public WebRuntime(
|
||||
Configs configs,
|
||||
IUmbracoVersion umbracoVersion,
|
||||
IIOHelper ioHelper,
|
||||
ILogger logger,
|
||||
IProfiler profiler,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IBackOfficeInfo backOfficeInfo,
|
||||
IDbProviderFactoryCreator dbProviderFactoryCreator,
|
||||
IMainDom mainDom,
|
||||
ITypeFinder typeFinder,
|
||||
IRequestCache requestCache,
|
||||
IUmbracoBootPermissionChecker umbracoBootPermissionChecker):
|
||||
base(configs, umbracoVersion, ioHelper, logger, profiler ,umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder)
|
||||
{
|
||||
_requestCache = requestCache;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IFactory Configure(IRegister register)
|
||||
{
|
||||
|
||||
var profilingLogger = new ProfilingLogger(Logger, Profiler);
|
||||
var umbracoVersion = new UmbracoVersion();
|
||||
using (var timer = profilingLogger.TraceDuration<CoreRuntime>(
|
||||
$"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.",
|
||||
"Booted.",
|
||||
"Boot failed."))
|
||||
{
|
||||
Logger.Info<CoreRuntime>("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
|
||||
HostingEnvironment.SiteName,
|
||||
HostingEnvironment.ApplicationId,
|
||||
HostingEnvironment.ApplicationPhysicalPath,
|
||||
NetworkHelper.MachineName);
|
||||
Logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
|
||||
|
||||
var factory = base.Configure(register);
|
||||
|
||||
// now (and only now) is the time to switch over to perWebRequest scopes.
|
||||
// up until that point we may not have a request, and scoped services would
|
||||
// fail to resolve - but we run Initialize within a factory scope - and then,
|
||||
// here, we switch the factory to bind scopes to requests
|
||||
factory.EnablePerWebRequestScope();
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#region Getters
|
||||
|
||||
protected override AppCaches GetAppCaches() => new AppCaches(
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache()),
|
||||
// we need request based cache when running in web-based context
|
||||
_requestCache,
|
||||
new IsolatedCaches(type =>
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache())));
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Smidge;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Runtime;
|
||||
@@ -57,7 +59,7 @@ namespace Umbraco.Tests.Integration
|
||||
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());
|
||||
testHelper.MainDom, testHelper.GetTypeFinder(), NoAppCache.Instance);
|
||||
|
||||
// boot it!
|
||||
var factory = coreRuntime.Configure(umbracoContainer);
|
||||
@@ -99,7 +101,7 @@ namespace Umbraco.Tests.Integration
|
||||
|
||||
// Add it!
|
||||
services.AddUmbracoConfiguration(hostContext.Configuration);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, out _);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, null, out _);
|
||||
});
|
||||
|
||||
var host = await hostBuilder.StartAsync();
|
||||
@@ -138,7 +140,7 @@ namespace Umbraco.Tests.Integration
|
||||
|
||||
// Add it!
|
||||
services.AddUmbracoConfiguration(hostContext.Configuration);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, out _);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, null, out _);
|
||||
});
|
||||
|
||||
var host = await hostBuilder.StartAsync();
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
|
||||
// Add it!
|
||||
services.AddUmbracoConfiguration(hostContext.Configuration);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, out _);
|
||||
services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, null, out _);
|
||||
});
|
||||
|
||||
var host = await hostBuilder.StartAsync();
|
||||
|
||||
@@ -16,10 +16,10 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Runtime;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.PublishedContent;
|
||||
using Umbraco.Tests.Testing;
|
||||
@@ -47,10 +47,10 @@ namespace Umbraco.Tests.Routing
|
||||
HostingEnvironment);
|
||||
}
|
||||
|
||||
public class TestRuntime : WebRuntime
|
||||
public class TestRuntime : CoreRuntime
|
||||
{
|
||||
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.GetTypeFinder(), TestHelper.GetRequestCache(), new AspNetUmbracoBootPermissionChecker())
|
||||
: base(configs, umbracoVersion, ioHelper, Mock.Of<ILogger>(), Mock.Of<IProfiler>(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), TestHelper.GetRequestCache())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Examine;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
@@ -116,7 +117,7 @@ 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, TestHelper.GetTypeFinder())
|
||||
:base(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), NoAppCache.Instance)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
var runtimeState = new RuntimeState(logger, null, umbracoVersion, backOfficeInfo);
|
||||
var configs = TestHelper.GetConfigs();
|
||||
var variationContextAccessor = TestHelper.VariationContextAccessor;
|
||||
|
||||
|
||||
|
||||
// create the register and the composition
|
||||
var register = TestHelper.GetRegister();
|
||||
@@ -84,7 +84,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo);
|
||||
|
||||
// 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, typeFinder);
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder, NoAppCache.Instance);
|
||||
|
||||
// determine actual runtime level
|
||||
runtimeState.DetermineRuntimeLevel(databaseFactory, logger);
|
||||
@@ -278,7 +278,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo);
|
||||
|
||||
// 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, typeFinder);
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder, NoAppCache.Instance);
|
||||
|
||||
// get the components
|
||||
// all of them?
|
||||
@@ -322,8 +322,8 @@ namespace Umbraco.Tests.Runtimes
|
||||
Assert.AreEqual(0, results.Count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
@@ -71,7 +73,13 @@ namespace Umbraco.Web.Common.Extensions
|
||||
|
||||
var umbContainer = UmbracoServiceProviderFactory.UmbracoContainer;
|
||||
|
||||
services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly(), out factory);
|
||||
|
||||
IHttpContextAccessor httpContextAccessor = new HttpContextAccessor();
|
||||
services.AddSingleton<IHttpContextAccessor>(httpContextAccessor);
|
||||
|
||||
var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext.Items);
|
||||
|
||||
services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly(), requestCache, httpContextAccessor, out factory);
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -83,20 +91,28 @@ namespace Umbraco.Web.Common.Extensions
|
||||
/// <param name="webHostEnvironment"></param>
|
||||
/// <param name="umbContainer"></param>
|
||||
/// <param name="entryAssembly"></param>
|
||||
/// <param name="requestCache"></param>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly, out IFactory factory)
|
||||
public static IServiceCollection AddUmbracoCore(
|
||||
this IServiceCollection services,
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
IRegister umbContainer,
|
||||
Assembly entryAssembly,
|
||||
IRequestCache requestCache,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
out IFactory factory)
|
||||
{
|
||||
if (services is null) throw new ArgumentNullException(nameof(services));
|
||||
var container = umbContainer;
|
||||
if (container is null) throw new ArgumentNullException(nameof(container));
|
||||
if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly));
|
||||
|
||||
// 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
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var configs = serviceProvider.GetService<Configs>();
|
||||
|
||||
CreateCompositionRoot(services, webHostEnvironment, out var logger, out var configs, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
|
||||
|
||||
CreateCompositionRoot(services, configs, httpContextAccessor, webHostEnvironment, out var logger, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
|
||||
|
||||
var globalSettings = configs.Global();
|
||||
var umbracoVersion = new UmbracoVersion(globalSettings);
|
||||
@@ -109,7 +125,8 @@ namespace Umbraco.Web.Common.Extensions
|
||||
profiler,
|
||||
hostingEnvironment,
|
||||
backOfficeInfo,
|
||||
CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly));
|
||||
CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly),
|
||||
requestCache);
|
||||
|
||||
factory = coreRuntime.Configure(container);
|
||||
|
||||
@@ -126,9 +143,10 @@ namespace Umbraco.Web.Common.Extensions
|
||||
return new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash);
|
||||
}
|
||||
|
||||
private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger,
|
||||
private static IRuntime GetCoreRuntime(
|
||||
Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger,
|
||||
IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
|
||||
ITypeFinder typeFinder)
|
||||
ITypeFinder typeFinder, IRequestCache requestCache)
|
||||
{
|
||||
var connectionStringConfig = configs.ConnectionStrings()[Constants.System.UmbracoConnectionName];
|
||||
var dbProviderFactoryCreator = new SqlServerDbProviderFactoryCreator(
|
||||
@@ -145,22 +163,27 @@ namespace Umbraco.Web.Common.Extensions
|
||||
|
||||
var mainDom = new MainDom(logger, mainDomLock);
|
||||
|
||||
var coreRuntime = new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, new AspNetCoreBootPermissionsChecker(),
|
||||
hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, typeFinder);
|
||||
var coreRuntime = new CoreRuntime(
|
||||
configs,
|
||||
umbracoVersion,
|
||||
ioHelper,
|
||||
logger,
|
||||
profiler,
|
||||
new AspNetCoreBootPermissionsChecker(),
|
||||
hostingEnvironment,
|
||||
backOfficeInfo,
|
||||
dbProviderFactoryCreator,
|
||||
mainDom,
|
||||
typeFinder,
|
||||
requestCache);
|
||||
|
||||
return coreRuntime;
|
||||
}
|
||||
|
||||
private static IServiceCollection CreateCompositionRoot(IServiceCollection services, IWebHostEnvironment webHostEnvironment,
|
||||
out ILogger logger, out Configs configs, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment,
|
||||
private static IServiceCollection CreateCompositionRoot(IServiceCollection services, Configs configs, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment,
|
||||
out ILogger logger, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment,
|
||||
out IBackOfficeInfo backOfficeInfo, out IProfiler profiler)
|
||||
{
|
||||
// TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
|
||||
var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
|
||||
|
||||
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)}");
|
||||
|
||||
@@ -216,4 +239,5 @@ namespace Umbraco.Web.Common.Extensions
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Threading;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -34,10 +37,12 @@ namespace Umbraco.Web
|
||||
|
||||
var mainDom = new MainDom(logger, mainDomLock);
|
||||
|
||||
var requestCache = new HttpRequestAppCache(() => HttpContext.Current?.Items);
|
||||
var requestCache = new HttpRequestAppCache(() => HttpContext.Current != null ? HttpContext.Current.Items : null);
|
||||
var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker();
|
||||
return new WebRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom,
|
||||
GetTypeFinder(hostingEnvironment, logger, profiler), requestCache, umbracoBootPermissionChecker);
|
||||
return new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom,
|
||||
GetTypeFinder(hostingEnvironment, logger, profiler), requestCache);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user