diff --git a/src/Umbraco.Core/Cache/GenericDictionaryRequestAppCache.cs b/src/Umbraco.Core/Cache/GenericDictionaryRequestAppCache.cs
new file mode 100644
index 0000000000..193235ca7e
--- /dev/null
+++ b/src/Umbraco.Core/Cache/GenericDictionaryRequestAppCache.cs
@@ -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
+{
+ ///
+ /// Implements a fast on top of HttpContext.Items.
+ ///
+ ///
+ /// 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.
+ ///
+ public class GenericDictionaryRequestAppCache : FastDictionaryAppCacheBase, IRequestCache
+ {
+ ///
+ /// Initializes a new instance of the class with a context, for unit tests!
+ ///
+ public GenericDictionaryRequestAppCache(Func> requestItems) : base()
+ {
+ ContextItems = requestItems;
+ }
+
+ private Func> ContextItems { get; }
+
+ public bool IsAvailable => TryGetContextItems(out _);
+
+ private bool TryGetContextItems(out IDictionary items)
+ {
+ items = ContextItems?.Invoke();
+ return items != null;
+ }
+
+ ///
+ public override object Get(string key, Func factory)
+ {
+ //no place to cache so just return the callback result
+ if (!TryGetContextItems(out var items)) return factory();
+
+ key = GetCacheKey(key);
+
+ Lazy result;
+
+ try
+ {
+ EnterWriteLock();
+ result = items[key] as Lazy; // 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 GetDictionaryEntries()
+ {
+ const string prefix = CacheItemPrefix + "-";
+
+ if (!TryGetContextItems(out var items)) return Enumerable.Empty();
+
+ return items.Cast()
+ .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> GetEnumerator()
+ {
+ if (!TryGetContextItems(out var items))
+ {
+ yield break;
+ }
+
+ foreach (var item in items)
+ {
+ yield return new KeyValuePair(item.Key.ToString(), item.Value);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+}
diff --git a/src/Umbraco.Core/Net/NullSessionIdResolver.cs b/src/Umbraco.Core/Net/NullSessionIdResolver.cs
new file mode 100644
index 0000000000..6bfa578268
--- /dev/null
+++ b/src/Umbraco.Core/Net/NullSessionIdResolver.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Net
+{
+ public class NullSessionIdResolver : ISessionIdResolver
+ {
+ public string SessionId => null;
+ }
+}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
index 1ea08e3118..19d3716e1c 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs
@@ -29,6 +29,7 @@ using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Examine;
using Umbraco.Infrastructure.Media;
+using Umbraco.Net;
using Umbraco.Web;
using Umbraco.Web.Actions;
using Umbraco.Web.Cache;
@@ -351,10 +352,6 @@ namespace Umbraco.Core.Runtime
// register accessors for cultures
composition.RegisterUnique();
-
-
-
-
}
}
}
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 92e47771a6..ebd91f52a2 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -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,19 @@ namespace Umbraco.Core.Runtime
"Booted.",
"Boot failed."))
{
- Logger.Info("Booting Core");
+
+ Logger.Info("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
+ HostingEnvironment?.SiteName,
+ HostingEnvironment?.ApplicationId,
+ HostingEnvironment?.ApplicationPhysicalPath,
+ NetworkHelper.MachineName);
Logger.Debug("Runtime: {Runtime}", GetType().FullName);
// application environment
ConfigureUnhandledException();
- return _factory = Configure(register, timer);
+ _factory = Configure(register, timer);
+
+ return _factory;
}
}
@@ -151,7 +162,7 @@ namespace Umbraco.Core.Runtime
try
{
-
+
// run handlers
RuntimeOptions.DoRuntimeBoot(ProfilingLogger);
@@ -244,6 +255,13 @@ namespace Umbraco.Core.Runtime
// create & initialize the components
_components = _factory.GetInstance();
_components.Initialize();
+
+
+ // 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();
}
protected virtual void ConfigureUnhandledException()
@@ -350,7 +368,7 @@ namespace Umbraco.Core.Runtime
return new AppCaches(
new DeepCloneAppCache(new ObjectCacheAppCache()),
- NoAppCache.Instance,
+ _requestCache,
new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache())));
}
diff --git a/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs b/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
deleted file mode 100644
index fc2a019023..0000000000
--- a/src/Umbraco.Infrastructure/Runtime/WebRuntime.cs
+++ /dev/null
@@ -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
-{
- ///
- /// Represents the Web Umbraco runtime.
- ///
- /// On top of CoreRuntime, handles all of the web-related runtime aspects of Umbraco.
- public class WebRuntime : CoreRuntime
- {
- private readonly IRequestCache _requestCache;
-
- ///
- /// Initializes a new instance of the class.
- ///
- 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;
- }
-
- ///
- public override IFactory Configure(IRegister register)
- {
-
- var profilingLogger = new ProfilingLogger(Logger, Profiler);
- var umbracoVersion = new UmbracoVersion();
- using (var timer = profilingLogger.TraceDuration(
- $"Booting Umbraco {umbracoVersion.SemanticVersion.ToSemanticString()}.",
- "Booted.",
- "Boot failed."))
- {
- Logger.Info("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.",
- HostingEnvironment.SiteName,
- HostingEnvironment.ApplicationId,
- HostingEnvironment.ApplicationPhysicalPath,
- NetworkHelper.MachineName);
- Logger.Debug("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
- }
-}
-
diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs
index 9bc8d31ded..ad040c8ef1 100644
--- a/src/Umbraco.Tests.Integration/RuntimeTests.cs
+++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs
@@ -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, testHelper.GetLoggingConfiguration(), out _);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), 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, testHelper.GetLoggingConfiguration(), out _);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), out _);
});
var host = await hostBuilder.StartAsync();
diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
index f3a2bcf011..0137850408 100644
--- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
+++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
@@ -108,7 +108,7 @@ namespace Umbraco.Tests.Integration.Testing
// Add it!
services.AddUmbracoConfiguration(hostContext.Configuration);
- services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, testHelper.GetLoggingConfiguration(), out _);
+ services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), out _);
});
var host = await hostBuilder.StartAsync();
diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
index b900453a5e..960d355c0d 100644
--- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
+++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
@@ -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(), Mock.Of(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), TestHelper.GetRequestCache(), new AspNetUmbracoBootPermissionChecker())
+ : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), NoAppCache.Instance)
{
}
diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
index 488a4f6dad..0b90457b1e 100644
--- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
+++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
@@ -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)
{
}
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 1a4c7f2040..5100e2e21c 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -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);
}
-
-
+
+
}
}
diff --git a/src/Umbraco.Web.BackOffice/Filters/MinifyJavaScriptResultAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/MinifyJavaScriptResultAttribute.cs
index 0ed0fd658a..65c2be051f 100644
--- a/src/Umbraco.Web.BackOffice/Filters/MinifyJavaScriptResultAttribute.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/MinifyJavaScriptResultAttribute.cs
@@ -2,9 +2,7 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core.Hosting;
using Microsoft.Extensions.DependencyInjection;
-using Umbraco.Core.Runtime;
using Umbraco.Core.WebAssets;
-using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.Common.ActionResults;
namespace Umbraco.Web.BackOffice.Filters
@@ -14,10 +12,11 @@ namespace Umbraco.Web.BackOffice.Filters
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// logic before action goes here
- var hostingEnvironment = context.HttpContext.RequestServices.GetService();
+ var serviceProvider = context.HttpContext.RequestServices;
+ var hostingEnvironment = serviceProvider.GetService();
if (!hostingEnvironment.IsDebugMode)
{
- var runtimeMinifier = context.HttpContext.RequestServices.GetService();
+ var runtimeMinifier = serviceProvider.GetService();
if (context.Result is JavaScriptResult jsResult)
{
diff --git a/src/Umbraco.Web.Common/Constants/ViewConstants.cs b/src/Umbraco.Web.Common/Constants/ViewConstants.cs
new file mode 100644
index 0000000000..5da1a74f55
--- /dev/null
+++ b/src/Umbraco.Web.Common/Constants/ViewConstants.cs
@@ -0,0 +1,12 @@
+namespace Umbraco.Web.Common.Constants
+{
+ ///
+ /// constants
+ ///
+ internal static class ViewConstants
+ {
+ internal const string ViewLocation = "~/Views";
+
+ internal const string DataTokenCurrentViewContext = "umbraco-current-view-context";
+ }
+}
diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs
new file mode 100644
index 0000000000..43058616de
--- /dev/null
+++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Umbraco.Web.Common.Controllers
+{
+ public abstract class RenderController : Controller
+ {
+
+ }
+}
diff --git a/src/Umbraco.Web.Common/Events/ActionExecutedEventArgs.cs b/src/Umbraco.Web.Common/Events/ActionExecutedEventArgs.cs
new file mode 100644
index 0000000000..b33cbc7d8a
--- /dev/null
+++ b/src/Umbraco.Web.Common/Events/ActionExecutedEventArgs.cs
@@ -0,0 +1,17 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Umbraco.Web.Common.Events
+{
+ public class ActionExecutedEventArgs : EventArgs
+ {
+ public Controller Controller { get; set; }
+ public object Model { get; set; }
+
+ public ActionExecutedEventArgs(Controller controller, object model)
+ {
+ Controller = controller;
+ Model = model;
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
index 2439243f30..3facf1b77f 100644
--- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Reflection;
@@ -80,7 +82,17 @@ namespace Umbraco.Web.Common.Extensions
Path.Combine(webHostEnvironment.ContentRootPath, "config\\serilog.config"),
Path.Combine(webHostEnvironment.ContentRootPath, "config\\serilog.user.config"));
- services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly(), loggingConfig, out factory);
+ IHttpContextAccessor httpContextAccessor = new HttpContextAccessor();
+ services.AddSingleton(httpContextAccessor);
+
+ var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext.Items);
+
+ services.AddUmbracoCore(webHostEnvironment,
+ umbContainer,
+ Assembly.GetEntryAssembly(),
+ requestCache,
+ loggingConfig,
+ out factory);
return services;
}
@@ -92,6 +104,8 @@ namespace Umbraco.Web.Common.Extensions
///
///
///
+ ///
+ ///
///
///
///
@@ -100,6 +114,7 @@ namespace Umbraco.Web.Common.Extensions
IWebHostEnvironment webHostEnvironment,
IRegister umbContainer,
Assembly entryAssembly,
+ IRequestCache requestCache,
ILoggingConfiguration loggingConfiguration,
out IFactory factory)
{
@@ -108,11 +123,15 @@ namespace Umbraco.Web.Common.Extensions
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();
+ var serviceProvider = services.BuildServiceProvider();
+ var configs = serviceProvider.GetService();
- CreateCompositionRoot(services, webHostEnvironment, loggingConfiguration, out var logger, out var configs, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
+
+ CreateCompositionRoot(services,
+ configs,
+ webHostEnvironment,
+ loggingConfiguration,
+ out var logger, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
var globalSettings = configs.Global();
var umbracoVersion = new UmbracoVersion(globalSettings);
@@ -125,7 +144,8 @@ namespace Umbraco.Web.Common.Extensions
profiler,
hostingEnvironment,
backOfficeInfo,
- CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly));
+ CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly),
+ requestCache);
factory = coreRuntime.Configure(container);
@@ -142,11 +162,12 @@ namespace Umbraco.Web.Common.Extensions
return new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash);
}
- private static IRuntime GetCoreRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, Core.Logging.ILogger logger,
+ private static IRuntime GetCoreRuntime(
+ Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, Core.Logging.ILogger logger,
IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo,
- ITypeFinder typeFinder)
+ ITypeFinder typeFinder, IRequestCache requestCache)
{
- var connectionStringConfig = configs.ConnectionStrings()[Constants.System.UmbracoConnectionName];
+ var connectionStringConfig = configs.ConnectionStrings()[Core.Constants.System.UmbracoConnectionName];
var dbProviderFactoryCreator = new SqlServerDbProviderFactoryCreator(
connectionStringConfig?.ProviderName,
DbProviderFactories.GetFactory);
@@ -161,23 +182,34 @@ 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,
+ Configs configs,
IWebHostEnvironment webHostEnvironment,
- ILoggingConfiguration loggingConfiguration,
- out Core.Logging.ILogger logger, out Configs configs, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment,
- out IBackOfficeInfo backOfficeInfo, out IProfiler profiler)
+ ILoggingConfiguration loggingConfiguration,
+ out Core.Logging.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();
-
- configs = serviceProvider.GetService();
if (configs == null)
throw new InvalidOperationException($"Could not resolve type {typeof(Configs)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}");
@@ -205,13 +237,13 @@ namespace Umbraco.Web.Common.Extensions
// Wire up all the bits that serilog needs. We need to use our own code since the Serilog ext methods don't cater to our needs since
// we don't want to use the global serilog `Log` object and we don't have our own ILogger implementation before the HostBuilder runs which
- // is the only other option that these ext methods allow.
+ // is the only other option that these ext methods allow.
// I have created a PR to make this nicer https://github.com/serilog/serilog-extensions-hosting/pull/19 but we'll need to wait for that.
// Also see : https://github.com/serilog/serilog-extensions-hosting/blob/dev/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs
services.AddSingleton(services => new SerilogLoggerFactory(logger.SerilogLog, false));
- // This won't (and shouldn't) take ownership of the logger.
+ // This won't (and shouldn't) take ownership of the logger.
services.AddSingleton(logger.SerilogLog);
// Registered to provide two services...
@@ -229,7 +261,7 @@ namespace Umbraco.Web.Common.Extensions
public static IServiceCollection AddUmbracoRuntimeMinifier(this IServiceCollection services,
IConfiguration configuration)
{
- services.AddSmidge(configuration.GetSection(Constants.Configuration.ConfigRuntimeMinification));
+ services.AddSmidge(configuration.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification));
services.AddSmidgeNuglify();
return services;
@@ -260,4 +292,5 @@ namespace Umbraco.Web.Common.Extensions
}
+
}
diff --git a/src/Umbraco.Web.Common/Filters/DisableBrowserCacheAttribute.cs b/src/Umbraco.Web.Common/Filters/DisableBrowserCacheAttribute.cs
new file mode 100644
index 0000000000..0fe251bac4
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/DisableBrowserCacheAttribute.cs
@@ -0,0 +1,35 @@
+using System;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Net.Http.Headers;
+
+namespace Umbraco.Web.Common.Filters
+{
+ ///
+ /// Ensures that the request is not cached by the browser
+ ///
+ public class DisableBrowserCacheAttribute : ActionFilterAttribute
+ {
+ public override void OnResultExecuting(ResultExecutingContext context)
+ {
+ base.OnResultExecuting(context);
+
+ var httpResponse = context.HttpContext.Response;
+
+ if (httpResponse.StatusCode != 200) return;
+
+ httpResponse.GetTypedHeaders().CacheControl =
+ new CacheControlHeaderValue()
+ {
+ NoCache = true,
+ MaxAge = TimeSpan.Zero,
+ MustRevalidate = true,
+ NoStore = true
+ };
+
+ httpResponse.Headers[HeaderNames.LastModified] = DateTime.Now.ToString("R"); // Format RFC1123
+ httpResponse.Headers[HeaderNames.Pragma] = "no-cache";
+ httpResponse.Headers[HeaderNames.Expires] = new DateTime(1990, 1, 1, 0, 0, 0).ToString("R");
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs
new file mode 100644
index 0000000000..269e437d0d
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs
@@ -0,0 +1,88 @@
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewEngines;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Umbraco.Web.Common.Constants;
+using Umbraco.Web.Common.Controllers;
+
+namespace Umbraco.Web.Common.Filters
+{
+ ///
+ /// This is a special filter which is required for the RTE to be able to render Partial View Macros that
+ /// contain forms when the RTE value is resolved outside of an MVC view being rendered
+ ///
+ ///
+ /// The entire way that we support partial view macros that contain forms isn't really great, these forms
+ /// need to be executed as ChildActions so that the ModelState,ViewData,TempData get merged into that action
+ /// so the form can show errors, viewdata, etc...
+ /// Under normal circumstances, macros will be rendered after a ViewContext is created but in some cases
+ /// developers will resolve the RTE value in the controller, in this case the Form won't be rendered correctly
+ /// with merged ModelState from the controller because the special DataToken hasn't been set yet (which is
+ /// normally done in the UmbracoViewPageOfModel when a real ViewContext is available.
+ /// So we need to detect if the currently rendering controller is IRenderController and if so we'll ensure that
+ /// this DataToken exists before the action executes in case the developer resolves an RTE value that contains
+ /// a partial view macro form.
+ ///
+ public class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute
+ {
+
+ ///
+ /// Ensures the custom ViewContext datatoken is set before the RenderController action is invoked,
+ /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still
+ /// render any PartialViewMacro with a form and maintain ModelState
+ ///
+ ///
+ public override void OnActionExecuting(ActionExecutingContext context)
+ {
+ if (!(context.Controller is Controller controller)) return;
+
+ //ignore anything that is not IRenderController
+ if (!(controller is RenderController)) return;
+
+ SetViewContext(context, controller);
+ }
+
+ ///
+ /// Ensures that the custom ViewContext datatoken is set after the RenderController action is invoked,
+ /// this ensures that any custom ModelState that may have been added in the RenderController itself is
+ /// passed onwards in case it is required when rendering a PartialViewMacro with a form
+ ///
+ /// The filter context.
+ public override void OnResultExecuting(ResultExecutingContext context)
+ {
+ if (!(context.Controller is Controller controller)) return;
+
+ //ignore anything that is not IRenderController
+ if (!(controller is RenderController)) return;
+
+ SetViewContext(context, controller);
+ }
+
+ private void SetViewContext(ActionContext context, Controller controller)
+ {
+ var viewCtx = new ViewContext(
+ context,
+ new DummyView(),
+ controller.ViewData,
+ controller.TempData,
+ new StringWriter(),
+ new HtmlHelperOptions());
+
+ //set the special data token
+ context.RouteData.DataTokens[ViewConstants.DataTokenCurrentViewContext] = viewCtx;
+ }
+
+ private class DummyView : IView
+ {
+ public Task RenderAsync(ViewContext context)
+ {
+ return Task.CompletedTask;
+ }
+
+ public string Path { get; }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs
new file mode 100644
index 0000000000..2ba58a8fd7
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/PreRenderViewActionFilterAttribute.cs
@@ -0,0 +1,43 @@
+using System;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Umbraco.Web.Common.Events;
+
+namespace Umbraco.Web.Common.Filters
+{
+ public class PreRenderViewActionFilterAttribute : ActionFilterAttribute
+ {
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ if (!(context.Controller is Controller umbController) || !(context.Result is ViewResult result))
+ {
+ return;
+ }
+
+ var model = result.Model;
+ if (model == null)
+ {
+ return;
+ }
+
+ var args = new ActionExecutedEventArgs(umbController, model);
+ OnActionExecuted(args);
+
+ if (args.Model != model)
+ {
+ result.ViewData.Model = args.Model;
+ }
+
+ base.OnActionExecuted(context);
+ }
+
+
+ public static event EventHandler ActionExecuted;
+
+ private static void OnActionExecuted(ActionExecutedEventArgs e)
+ {
+ var handler = ActionExecuted;
+ handler?.Invoke(null, e);
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs
new file mode 100644
index 0000000000..8f3fcf3a95
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs
@@ -0,0 +1,39 @@
+using System.Net;
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Core.Configuration.UmbracoSettings;
+
+namespace Umbraco.Web.Common.Filters
+{
+ ///
+ /// Forces the response to have a specific http status code
+ ///
+ public class StatusCodeResultAttribute : ActionFilterAttribute
+ {
+ private readonly HttpStatusCode _statusCode;
+
+ public StatusCodeResultAttribute(HttpStatusCode statusCode)
+ {
+ _statusCode = statusCode;
+ }
+
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ base.OnActionExecuted(context);
+
+ var httpContext = context.HttpContext;
+
+ httpContext.Response.StatusCode = (int)_statusCode;
+
+ var disableIisCustomErrors = httpContext.RequestServices.GetService().TrySkipIisCustomErrors;
+ var statusCodePagesFeature = httpContext.Features.Get();
+
+ if (statusCodePagesFeature != null)
+ {
+ // if IIS Custom Errors are disabled, we won't enable the Status Code Pages
+ statusCodePagesFeature.Enabled = !disableIisCustomErrors;
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
index ba3c6c289f..c4b9522099 100644
--- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
+++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
@@ -112,7 +112,7 @@ namespace Umbraco.Web.Common.RuntimeMinification
public void Reset()
{
var version = DateTime.UtcNow.Ticks.ToString();
- _configManipulator.SaveConfigValue(Constants.Configuration.ConfigRuntimeMinificationVersion, version.ToString());
+ _configManipulator.SaveConfigValue(Core.Constants.Configuration.ConfigRuntimeMinificationVersion, version.ToString());
}
diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs
index 8602d5bed6..37440006aa 100644
--- a/src/Umbraco.Web.UI.NetCore/Startup.cs
+++ b/src/Umbraco.Web.UI.NetCore/Startup.cs
@@ -76,6 +76,7 @@ namespace Umbraco.Web.UI.BackOffice
{
app.UseDeveloperExceptionPage();
}
+ app.UseStatusCodePages();
app.UseUmbracoCore();
app.UseUmbracoRequestLogging();
app.UseUmbracoWebsite();
diff --git a/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs b/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs
index 1c596ff80c..6904aa103a 100644
--- a/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs
+++ b/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs
@@ -3,6 +3,7 @@ using System.Web.Mvc;
namespace Umbraco.Web.Mvc
{
+ /// Migrated already to .Net Core
public class ActionExecutedEventArgs : EventArgs
{
public Controller Controller { get; set; }
diff --git a/src/Umbraco.Web/Mvc/Constants.cs b/src/Umbraco.Web/Mvc/Constants.cs
index 1794345746..c71ed6b104 100644
--- a/src/Umbraco.Web/Mvc/Constants.cs
+++ b/src/Umbraco.Web/Mvc/Constants.cs
@@ -3,6 +3,7 @@
///
/// constants
///
+ /// Migrated already to .Net Core
internal static class Constants
{
internal const string ViewLocation = "~/Views";
diff --git a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs
index 34b857dfb4..f443abbb70 100644
--- a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs
+++ b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs
@@ -19,6 +19,7 @@ namespace Umbraco.Web.Mvc
/// this DataToken exists before the action executes in case the developer resolves an RTE value that contains
/// a partial view macro form.
///
+ /// Migrated already to .Net Core
internal class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute
{
///
diff --git a/src/Umbraco.Web/Mvc/IRenderController.cs b/src/Umbraco.Web/Mvc/IRenderController.cs
index 103a484869..0de585959c 100644
--- a/src/Umbraco.Web/Mvc/IRenderController.cs
+++ b/src/Umbraco.Web/Mvc/IRenderController.cs
@@ -5,6 +5,7 @@ namespace Umbraco.Web.Mvc
///
/// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking
///
+ /// Migrated already to .Net Core
public interface IRenderController : IController
{
diff --git a/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs b/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs
index 227c15b344..635a7314c5 100644
--- a/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs
+++ b/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs
@@ -12,6 +12,7 @@ namespace Umbraco.Web.Mvc
///
/// Only minifies in release mode
///
+ /// Migrated already to .Net Core
public class MinifyJavaScriptResultAttribute : ActionFilterAttribute
{
private readonly IHostingEnvironment _hostingEnvironment;
diff --git a/src/Umbraco.Web/Mvc/PreRenderViewActionFilterAttribute.cs b/src/Umbraco.Web/Mvc/PreRenderViewActionFilterAttribute.cs
index 54e20f5d56..2e659eccf6 100644
--- a/src/Umbraco.Web/Mvc/PreRenderViewActionFilterAttribute.cs
+++ b/src/Umbraco.Web/Mvc/PreRenderViewActionFilterAttribute.cs
@@ -3,6 +3,7 @@ using System.Web.Mvc;
namespace Umbraco.Web.Mvc
{
+ /// Migrated already to .Net Core
public class PreRenderViewActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
diff --git a/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs b/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs
index b1836c6ba4..727c29b93c 100644
--- a/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs
+++ b/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs
@@ -8,6 +8,7 @@ namespace Umbraco.Web.Mvc
///
/// Forces the response to have a specific http status code
///
+ /// Migrated already to .Net Core
internal class StatusCodeResultAttribute : ActionFilterAttribute
{
private readonly HttpStatusCode _statusCode;
diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs
index cd72b2faf9..7679da2e2e 100644
--- a/src/Umbraco.Web/UmbracoApplication.cs
+++ b/src/Umbraco.Web/UmbracoApplication.cs
@@ -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);
}
+
+
}
}