Merge branch 'netcore/feature/use-request-cache-instead-of-httpcontext-items' into netcore/feature/move-files-after-umbraco-context-abstractions

This commit is contained in:
Bjarke Berg
2020-02-13 11:40:56 +01:00
52 changed files with 330 additions and 220 deletions
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text.RegularExpressions;
@@ -101,5 +102,9 @@ namespace Umbraco.Core.Cache
var compiled = new Regex(regex, RegexOptions.Compiled);
_items.RemoveAll(kvp => compiled.IsMatch(kvp.Key));
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
@@ -171,5 +171,20 @@ namespace Umbraco.Core.Cache
}
#endregion
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
if (!TryGetContextItems(out var items))
{
yield break;
}
foreach (DictionaryEntry item in items)
{
yield return new KeyValuePair<string, object>(item.Key.ToString(), item.Value);
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
@@ -1,6 +1,8 @@
using System.Collections.Generic;
namespace Umbraco.Core.Cache
{
public interface IRequestCache : IAppCache
public interface IRequestCache : IAppCache, IEnumerable<KeyValuePair<string, object>>
{
bool Set(string key, object value);
bool Remove(string key);
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -84,5 +85,9 @@ namespace Umbraco.Core.Cache
/// <inheritdoc />
public virtual void ClearByRegex(string regex)
{ }
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => new Dictionary<string, object>().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
@@ -1,6 +1,7 @@
using System;
using System.Runtime.Remoting.Messaging;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Scoping;
namespace Umbraco.Web
{
@@ -16,12 +17,14 @@ namespace Umbraco.Web
public abstract class HybridAccessorBase<T>
where T : class
{
private readonly IRequestCache _requestCache;
// ReSharper disable StaticMemberInGenericType
private static readonly object Locker = new object();
private static bool _registered;
// ReSharper restore StaticMemberInGenericType
private readonly IHttpContextAccessor _httpContextAccessor;
// private readonly IHttpContextAccessor _httpContextAccessor;
protected abstract string ItemKey { get; }
@@ -42,17 +45,16 @@ namespace Umbraco.Web
// yes! flows with async!
private T NonContextValue
{
get => (T) CallContext.LogicalGetData(ItemKey);
get => CallContext<T>.GetData(ItemKey);
set
{
if (value == null) CallContext.FreeNamedDataSlot(ItemKey);
else CallContext.LogicalSetData(ItemKey, value);
CallContext<T>.SetData(ItemKey, value);
}
}
protected HybridAccessorBase(IHttpContextAccessor httpContextAccessor)
protected HybridAccessorBase(IRequestCache requestCache)
{
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
_requestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache));
lock (Locker)
{
@@ -65,15 +67,14 @@ namespace Umbraco.Web
var itemKey = ItemKey; // virtual
SafeCallContext.Register(() =>
{
var value = CallContext.LogicalGetData(itemKey);
CallContext.FreeNamedDataSlot(itemKey);
var value = CallContext<T>.GetData(itemKey);
return value;
}, o =>
{
if (o == null) return;
var value = o as T;
if (value == null) throw new ArgumentException($"Expected type {typeof(T).FullName}, got {o.GetType().FullName}", nameof(o));
CallContext.LogicalSetData(itemKey, value);
CallContext<T>.SetData(itemKey, value);
});
}
@@ -81,20 +82,23 @@ namespace Umbraco.Web
{
get
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return NonContextValue;
return (T) httpContext.Items[ItemKey];
if (!_requestCache.IsAvailable)
{
return NonContextValue;
}
return (T) _requestCache.Get(ItemKey);
}
set
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null)
if (!_requestCache.IsAvailable)
{
NonContextValue = value;
}
else if (value == null)
httpContext.Items.Remove(ItemKey);
_requestCache.Remove(ItemKey);
else
httpContext.Items[ItemKey] = value;
_requestCache.Set(ItemKey, value);
}
}
}
@@ -1,4 +1,5 @@
using Umbraco.Core.Events;
using Umbraco.Core.Cache;
using Umbraco.Core.Events;
namespace Umbraco.Web
{
@@ -6,8 +7,8 @@ namespace Umbraco.Web
{
protected override string ItemKey => "Umbraco.Core.Events.HybridEventMessagesAccessor";
public HybridEventMessagesAccessor(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
public HybridEventMessagesAccessor(IRequestCache requestCache)
: base(requestCache)
{ }
public EventMessages EventMessages
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models.PublishedContent
{
@@ -7,22 +8,22 @@ namespace Umbraco.Web.Models.PublishedContent
/// </summary>
public class HttpContextVariationContextAccessor : IVariationContextAccessor
{
public const string ContextKey = "Umbraco.Web.Models.PublishedContent.DefaultVariationContextAccessor";
public readonly IHttpContextAccessor HttpContextAccessor;
private readonly IRequestCache _requestCache;
private const string _contextKey = "Umbraco.Web.Models.PublishedContent.DefaultVariationContextAccessor";
/// <summary>
/// Initializes a new instance of the <see cref="HttpContextVariationContextAccessor"/> class.
/// </summary>
public HttpContextVariationContextAccessor(IHttpContextAccessor httpContextAccessor)
public HttpContextVariationContextAccessor(IRequestCache requestCache)
{
HttpContextAccessor = httpContextAccessor;
_requestCache = requestCache;
}
/// <inheritdoc />
public VariationContext VariationContext
{
get => (VariationContext) HttpContextAccessor.HttpContext?.Items[ContextKey];
set => HttpContextAccessor.HttpContext.Items[ContextKey] = value;
get => (VariationContext) _requestCache.Get(_contextKey);
set => _requestCache.Set(_contextKey, value);
}
}
}
@@ -14,14 +14,16 @@ namespace Umbraco.Web.Models.PublishedContent
{
private readonly ILocalizationService _localizationService;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IPublishedValueFallback _publishedValueFallback;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedValueFallback"/> class.
/// </summary>
public PublishedValueFallback(ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor)
public PublishedValueFallback(ServiceContext serviceContext, IVariationContextAccessor variationContextAccessor, IPublishedValueFallback publishedValueFallback)
{
_localizationService = serviceContext.LocalizationService;
_variationContextAccessor = variationContextAccessor;
_publishedValueFallback = publishedValueFallback;
}
/// <inheritdoc />
@@ -182,7 +184,7 @@ namespace Umbraco.Web.Models.PublishedContent
// if we found a content with the property having a value, return that property value
if (property != null && property.HasValue(culture, segment))
{
value = property.Value<T>(culture, segment);
value = property.Value<T>(_publishedValueFallback, culture, segment);
return true;
}
@@ -216,7 +218,7 @@ namespace Umbraco.Web.Models.PublishedContent
if (property.HasValue(culture2, segment))
{
value = property.Value<T>(culture2, segment);
value = property.Value<T>(_publishedValueFallback, culture2, segment);
return true;
}
@@ -250,7 +252,7 @@ namespace Umbraco.Web.Models.PublishedContent
if (content.HasValue(alias, culture2, segment))
{
value = content.Value<T>(alias, culture2, segment);
value = content.Value<T>(_publishedValueFallback, alias, culture2, segment);
return true;
}
@@ -287,7 +289,7 @@ namespace Umbraco.Web.Models.PublishedContent
if (content.HasValue(alias, culture2, segment))
{
value = content.Value<T>(alias, culture2, segment);
value = content.Value<T>(_publishedValueFallback, alias, culture2, segment);
return true;
}
@@ -1,6 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Umbraco.Core;
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.Models.Trees
@@ -24,9 +24,4 @@
<_Parameter1>Umbraco.Tests.Benchmarks</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<Folder Include="Logging\Viewer" />
</ItemGroup>
</Project>
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Web.Models
{
internal class ImageProcessorImageUrlGenerator : IImageUrlGenerator
public class ImageProcessorImageUrlGenerator : IImageUrlGenerator
{
public string GetImageUrl(ImageUrlGenerationOptions options)
{
@@ -20,6 +20,7 @@ using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Web.Models.PublishedContent;
using Umbraco.Web.PublishedCache;
using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator;
@@ -141,6 +142,8 @@ namespace Umbraco.Core.Runtime
// register the published snapshot accessor - the "current" published snapshot is in the umbraco context
composition.RegisterUnique<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
composition.RegisterUnique<IVariationContextAccessor, HybridVariationContextAccessor>();
}
}
}
@@ -439,11 +439,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache, variationContextAccessor)).CreateModel(Current.PublishedModelFactory));
}
public static void ClearRequest()
{
Current.AppCaches.RequestCache.ClearByKey(CacheKeyPrefix);
}
private const string CacheKeyPrefix = "CONTENTCACHE_XMLPUBLISHEDCONTENT_";
}
}
@@ -42,7 +42,8 @@ namespace Umbraco.Tests.Routing
logger,
null, // FIXME: PublishedRouter complexities...
Mock.Of<IUmbracoContextFactory>(),
new RoutableDocumentFilter(globalSettings, IOHelper)
new RoutableDocumentFilter(globalSettings, IOHelper),
AppCaches.RequestCache
);
runtime.Level = RuntimeLevel.Run;
@@ -8,7 +8,6 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Web.Composing;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web;
@@ -39,7 +38,7 @@ namespace Umbraco.Tests.Security
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Install);
var mgr = new BackOfficeCookieManager(
Mock.Of<IUmbracoContextAccessor>(accessor => accessor.UmbracoContext == umbracoContext), runtime, TestObjects.GetGlobalSettings(), TestHelper.IOHelper);
Mock.Of<IUmbracoContextAccessor>(accessor => accessor.UmbracoContext == umbracoContext), runtime, TestObjects.GetGlobalSettings(), IOHelper, AppCaches.RequestCache);
var result = mgr.ShouldAuthenticateRequest(Mock.Of<IOwinContext>(), new Uri("http://localhost/umbraco"));
@@ -58,7 +57,7 @@ namespace Umbraco.Tests.Security
new TestVariationContextAccessor(), IOHelper);
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
var mgr = new BackOfficeCookieManager(Mock.Of<IUmbracoContextAccessor>(accessor => accessor.UmbracoContext == umbCtx), runtime, TestObjects.GetGlobalSettings(), TestHelper.IOHelper);
var mgr = new BackOfficeCookieManager(Mock.Of<IUmbracoContextAccessor>(accessor => accessor.UmbracoContext == umbCtx), runtime, TestObjects.GetGlobalSettings(), IOHelper, AppCaches.RequestCache);
var request = new Mock<OwinRequest>();
request.Setup(owinRequest => owinRequest.Uri).Returns(new Uri("http://localhost/umbraco"));
@@ -29,6 +29,7 @@ namespace Umbraco.Tests.TestHelpers
protected override void Compose()
{
base.Compose();
base.Compose();
Composition.RegisterUnique<IPublishedValueFallback, PublishedValueFallback>();
Composition.RegisterUnique<IProfilingLogger, ProfilingLogger>();
+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="Umbraco.Web" />
<add namespace="Umbraco.Core" />
<add namespace="Umbraco.Core.Models" />
<add namespace="Umbraco.Core.Models.PublishedContent" />
<add namespace="Umbraco.Web.Mvc" />
<add namespace="Examine" />
<add namespace="Umbraco.Web.PublishedModels" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
<system.web>
<compilation targetFramework="4.7.2">
<assemblies>
<add assembly="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<!--
Views are compiled by the Microsoft.CodeDom.Providers.DotNetCompilerPlatform which uses the Roslyn compiler
from ~/bin/roslyn to expose an ICodeProvider implementation to System.CodeDom.
For instance, starting with package 1.4.0 (which contains version 1.2.2.0) System.Collections.Immutable
lists netstandard2.0 as a supported target, whereas package 1.3.1 only listed net45. So now, when
installing, NuGet picks the netstandard2.0 version, thus introducing a dependency to netstandard2.0.
Somehow, transitive dependencies are not working correctly, and either (a) NuGet fails to properly
register this dependency, or (b) when reference assemblies are gathered before compiling views, this
dependency is missed. In any case, the result is that the ICodeProvider is passed a list of referenced
assemblies that is missing .NET Standard.
It may be a mix of both. NuGet registers the dependency well enough, that we can actually build the
whole application - but it is not doing something that is required in order to have .NET Standard
being a dependency when building views.
See also: https://stackoverflow.com/questions/50165910
Funny enough, the CSharpCompiler already explicitly adds System.Runtime as a referenced assembly,
with a comment mentioning an issue. But it's not adding .NET Standard. So, for the time being, to be sure,
we are adding both here.
-->
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add assembly="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
</assemblies>
</compilation>
</system.web>
</configuration>
@@ -48,7 +48,7 @@
redirectUrl = Url.Action("AuthorizeUpgrade", "BackOffice")
});
}
@Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection)
@Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection, Model.HttpContextAccessor, Model.HostingEnvironment)
<script type="text/javascript">
document.angularReady = function (app) {
@@ -110,7 +110,7 @@
on-login="hideLoginScreen()">
</umb-login>
@Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewData.GetUmbracoPath() }), Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection)
@Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewData.GetUmbracoPath() }), Model.Features, Model.GlobalSettings, Model.UmbracoVersion, Model.UmbracoSettingsSection, Model.IOHelper, Model.TreeCollection, Model.HttpContextAccessor, Model.HostingEnvironment)
<script>
@@ -28,22 +28,14 @@ namespace Umbraco.Web
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
{
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IRequestCache _requestCache;
public BatchedDatabaseServerMessenger(
IRuntimeState runtime,
IUmbracoDatabaseFactory databaseFactory,
IScopeProvider scopeProvider,
ISqlContext sqlContext,
IProfilingLogger proflog,
DatabaseServerMessengerOptions options,
IHostingEnvironment hostingEnvironment,
CacheRefresherCollection cacheRefreshers,
IHttpContextAccessor httpContextAccessor)
IRuntimeState runtime, IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IRequestCache requestCache)
: base(runtime, scopeProvider, sqlContext, proflog, true, options, hostingEnvironment, cacheRefreshers)
{
_databaseFactory = databaseFactory;
_httpContextAccessor = httpContextAccessor;
_requestCache = requestCache;
}
// invoked by DatabaseServerRegistrarAndMessengerComponent
@@ -112,24 +104,18 @@ namespace Umbraco.Web
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
{
// try get the http context from the UmbracoContext, we do this because in the case we are launching an async
// thread and we know that the cache refreshers will execute, we will ensure the UmbracoContext and therefore we
// can get the http context from it
var httpContext = (_httpContextAccessor.HttpContext)
// if this is null, it could be that an async thread is calling this method that we weren't aware of and the UmbracoContext
// wasn't ensured at the beginning of the thread. We can try to see if the HttpContext.Current is available which might be
// the case if the asp.net synchronization context has kicked in
?? (HttpContext.Current == null ? null : new HttpContextWrapper(HttpContext.Current));
// if no context was found, return null - we cannot not batch
if (httpContext == null) return null;
var key = typeof (BatchedDatabaseServerMessenger).Name;
if (!_requestCache.IsAvailable) return null;
// no thread-safety here because it'll run in only 1 thread (request) at a time
var batch = (ICollection<RefreshInstructionEnvelope>)httpContext.Items[key];
var batch = (ICollection<RefreshInstructionEnvelope>)_requestCache.Get(key);
if (batch == null && create)
httpContext.Items[key] = batch = new List<RefreshInstructionEnvelope>();
{
batch = new List<RefreshInstructionEnvelope>();
_requestCache.Set(key, batch);
}
return batch;
}
+4 -1
View File
@@ -3,6 +3,7 @@ using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Umbraco.Core.Cache;
using Umbraco.Core.Hosting;
namespace Umbraco.Web
{
@@ -16,6 +17,7 @@ namespace Umbraco.Web
/// Outputs and caches a partial view in MVC
/// </summary>
/// <param name="appCaches"></param>
/// <param name="hostingEnvironment"></param>
/// <param name="htmlHelper"></param>
/// <param name="partialViewName"></param>
/// <param name="model"></param>
@@ -25,6 +27,7 @@ namespace Umbraco.Web
/// <returns></returns>
public static IHtmlString CachedPartialView(
this AppCaches appCaches,
IHostingEnvironment hostingEnvironment,
HtmlHelper htmlHelper,
string partialViewName,
object model,
@@ -33,7 +36,7 @@ namespace Umbraco.Web
ViewDataDictionary viewData = null)
{
//disable cached partials in debug mode: http://issues.umbraco.org/issue/U4-5940
if (htmlHelper.ViewContext.HttpContext.IsDebuggingEnabled)
if (hostingEnvironment.IsDebugMode)
{
// just return a normal partial view instead
return htmlHelper.Partial(partialViewName, model, viewData);
@@ -27,6 +27,7 @@ using Constants = Umbraco.Core.Constants;
using JArray = Newtonsoft.Json.Linq.JArray;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Web.Trees;
@@ -50,6 +51,8 @@ namespace Umbraco.Web.Editors
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly TreeCollection _treeCollection;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
public BackOfficeController(
IManifestParser manifestParser,
@@ -65,7 +68,9 @@ namespace Umbraco.Web.Editors
IGridConfig gridConfig,
IUmbracoSettingsSection umbracoSettingsSection,
IIOHelper ioHelper,
TreeCollection treeCollection)
TreeCollection treeCollection,
IHostingEnvironment hostingEnvironment,
IHttpContextAccessor httpContextAccessor)
: base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper)
{
_manifestParser = manifestParser;
@@ -76,6 +81,8 @@ namespace Umbraco.Web.Editors
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection));
_hostingEnvironment = hostingEnvironment;
_httpContextAccessor = httpContextAccessor;
}
protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager());
@@ -91,8 +98,8 @@ namespace Umbraco.Web.Editors
public async Task<ActionResult> Default()
{
return await RenderDefaultOrProcessExternalLoginAsync(
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection,_ioHelper, _treeCollection)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection)));
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection,_ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment)));
}
[HttpGet]
@@ -175,7 +182,7 @@ namespace Umbraco.Web.Editors
{
return await RenderDefaultOrProcessExternalLoginAsync(
//The default view to render when there is no external login info or errors
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment)),
//The ActionResult to perform if external login is successful
() => Redirect("/"));
}
@@ -255,7 +262,7 @@ namespace Umbraco.Web.Editors
}
//cache the result if debugging is disabled
var result = HttpContext.IsDebuggingEnabled
var result = _hostingEnvironment.IsDebugMode
? GetAssetList()
: AppCaches.RuntimeCache.GetCacheItem<JArray>(
"Umbraco.Web.Editors.BackOfficeController.GetManifestAssetList",
@@ -282,10 +289,10 @@ namespace Umbraco.Web.Editors
[MinifyJavaScriptResult(Order = 1)]
public JavaScriptResult ServerVariables()
{
var serverVars = new BackOfficeServerVariables(Url, _runtimeState, _features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection);
var serverVars = new BackOfficeServerVariables(Url, _runtimeState, _features, GlobalSettings, _umbracoVersion, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment);
//cache the result if debugging is disabled
var result = HttpContext.IsDebuggingEnabled
var result = _hostingEnvironment.IsDebugMode
? ServerVariablesParser.Parse(serverVars.GetServerVariables())
: AppCaches.RuntimeCache.GetCacheItem<string>(
typeof(BackOfficeController) + "ServerVariables",
+6 -1
View File
@@ -1,5 +1,6 @@
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Web.Features;
using Umbraco.Web.Trees;
@@ -9,7 +10,7 @@ namespace Umbraco.Web.Editors
public class BackOfficeModel
{
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection)
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment)
{
Features = features;
GlobalSettings = globalSettings;
@@ -17,6 +18,8 @@ namespace Umbraco.Web.Editors
UmbracoSettingsSection = umbracoSettingsSection;
IOHelper = ioHelper;
TreeCollection = treeCollection;
HttpContextAccessor = httpContextAccessor;
HostingEnvironment = hostingEnvironment;
}
public UmbracoFeatures Features { get; }
@@ -25,5 +28,7 @@ namespace Umbraco.Web.Editors
public IUmbracoSettingsSection UmbracoSettingsSection { get; }
public IIOHelper IOHelper { get; }
public TreeCollection TreeCollection { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
public IHostingEnvironment HostingEnvironment { get; }
}
}
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Web.Features;
@@ -13,8 +14,8 @@ namespace Umbraco.Web.Editors
private readonly UmbracoFeatures _features;
public IEnumerable<ILanguage> Languages { get; }
public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IEnumerable<ILanguage> languages, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection)
: base(features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection)
public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IEnumerable<ILanguage> languages, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment)
: base(features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment)
{
_features = features;
Languages = languages;
@@ -21,6 +21,7 @@ using Umbraco.Web.PropertyEditors;
using Umbraco.Web.Trees;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
namespace Umbraco.Web.Editors
@@ -34,25 +35,25 @@ namespace Umbraco.Web.Editors
private readonly IRuntimeState _runtimeState;
private readonly UmbracoFeatures _features;
private readonly IGlobalSettings _globalSettings;
private readonly HttpContextBase _httpContext;
private readonly IOwinContext _owinContext;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly TreeCollection _treeCollection;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IHostingEnvironment _hostingEnvironment;
internal BackOfficeServerVariables(UrlHelper urlHelper, IRuntimeState runtimeState, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection)
internal BackOfficeServerVariables(UrlHelper urlHelper, IRuntimeState runtimeState, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment)
{
_urlHelper = urlHelper;
_runtimeState = runtimeState;
_features = features;
_globalSettings = globalSettings;
_httpContext = _urlHelper.RequestContext.HttpContext;
_owinContext = _httpContext.GetOwinContext();
_umbracoVersion = umbracoVersion;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection));
_httpContextAccessor = httpContextAccessor;
_hostingEnvironment = hostingEnvironment;
}
/// <summary>
@@ -368,7 +369,7 @@ namespace Umbraco.Web.Editors
}
},
{
"isDebuggingEnabled", _httpContext.IsDebuggingEnabled
"isDebuggingEnabled", _hostingEnvironment.IsDebugMode
},
{
"application", GetApplicationState()
@@ -377,7 +378,7 @@ namespace Umbraco.Web.Editors
"externalLogins", new Dictionary<string, object>
{
{
"providers", _owinContext.Authentication.GetExternalAuthenticationTypes()
"providers", _httpContextAccessor.HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes()
.Where(p => p.Properties.ContainsKey("UmbracoBackOffice"))
.Select(p => new
{
@@ -464,7 +465,7 @@ namespace Umbraco.Web.Editors
app.Add("cacheBuster", $"{version}.{_runtimeState.Level}.{ClientDependencySettings.Instance.Version}".GenerateHash());
//useful for dealing with virtual paths on the client side when hosted in virtual directories especially
app.Add("applicationPath", _httpContext.Request.ApplicationPath.EnsureEndsWith('/'));
app.Add("applicationPath", _httpContextAccessor.HttpContext.Request.ApplicationPath.EnsureEndsWith('/'));
//add the server's GMT time offset in minutes
app.Add("serverTimeOffset", Convert.ToInt32(DateTimeOffset.Now.Offset.TotalMinutes));
+9 -2
View File
@@ -6,6 +6,7 @@ using System.Web.UI;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
@@ -31,6 +32,8 @@ namespace Umbraco.Web.Editors
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly TreeCollection _treeCollection;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IHostingEnvironment _hostingEnvironment;
public PreviewController(
UmbracoFeatures features,
@@ -41,7 +44,9 @@ namespace Umbraco.Web.Editors
IUmbracoVersion umbracoVersion,
IUmbracoSettingsSection umbracoSettingsSection,
IIOHelper ioHelper,
TreeCollection treeCollection)
TreeCollection treeCollection,
IHttpContextAccessor httpContextAccessor,
IHostingEnvironment hostingEnvironment)
{
_features = features;
_globalSettings = globalSettings;
@@ -52,6 +57,8 @@ namespace Umbraco.Web.Editors
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_treeCollection = treeCollection;
_httpContextAccessor = httpContextAccessor;
_hostingEnvironment = hostingEnvironment;
}
[UmbracoAuthorize(redirectToUmbracoLogin: true)]
@@ -60,7 +67,7 @@ namespace Umbraco.Web.Editors
{
var availableLanguages = _localizationService.GetAllLanguages();
var model = new BackOfficePreviewModel(_features, _globalSettings, _umbracoVersion, availableLanguages, _umbracoSettingsSection, _ioHelper, _treeCollection);
var model = new BackOfficePreviewModel(_features, _globalSettings, _umbracoVersion, availableLanguages, _umbracoSettingsSection, _ioHelper, _treeCollection, _httpContextAccessor, _hostingEnvironment);
if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false)
{
@@ -5,6 +5,7 @@ using System.Web;
using System.Web.Mvc;
using Microsoft.Owin.Security;
using Newtonsoft.Json;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Web.Composing;
using Umbraco.Web.Editors;
@@ -39,9 +40,9 @@ namespace Umbraco.Web
/// These are the bare minimal server variables that are required for the application to start without being authenticated,
/// we will load the rest of the server vars after the user is authenticated.
/// </remarks>
public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection)
public static IHtmlString BareMinimumServerVariablesScript(this HtmlHelper html, UrlHelper uri, string externalLoginsUrl, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, TreeCollection treeCollection, IHttpContextAccessor httpContextAccessor, IHostingEnvironment hostingEnvironment)
{
var serverVars = new BackOfficeServerVariables(uri, Current.RuntimeState, features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection);
var serverVars = new BackOfficeServerVariables(uri, Current.RuntimeState, features, globalSettings, umbracoVersion, umbracoSettingsSection, ioHelper, treeCollection, httpContextAccessor, hostingEnvironment);
var minVars = serverVars.BareMinimumServerVariables();
var str = @"<script type=""text/javascript"">
@@ -105,7 +105,7 @@ namespace Umbraco.Web
var contextualKey = contextualKeyBuilder(model, viewData);
cacheKey.AppendFormat("c{0}-", contextualKey);
}
return Current.AppCaches.CachedPartialView(htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData);
return Current.AppCaches.CachedPartialView(Current.HostingEnvironment, htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData);
}
public static MvcHtmlString EditorFor<T>(this HtmlHelper htmlHelper, string templateName = "", string htmlFieldName = "", object additionalViewData = null)
-14
View File
@@ -4,20 +4,6 @@ namespace Umbraco.Core
{
public static class HttpContextExtensions
{
public static T GetContextItem<T>(this HttpContextBase httpContext, string key)
{
if (httpContext == null) return default(T);
if (httpContext.Items[key] == null) return default(T);
var val = httpContext.Items[key].TryConvertTo<T>();
if (val) return val.Result;
return default(T);
}
public static T GetContextItem<T>(this HttpContext httpContext, string key)
{
return new HttpContextWrapper(httpContext).GetContextItem<T>(key);
}
public static string GetCurrentRequestIpAddress(this HttpContextBase httpContext)
{
if (httpContext == null)
@@ -1,31 +1,29 @@
using System;
using Umbraco.Core.Cache;
namespace Umbraco.Web
{
internal class HttpContextUmbracoContextAccessor : IUmbracoContextAccessor
{
private readonly IRequestCache _requestCache;
private const string HttpContextItemKey = "Umbraco.Web.UmbracoContext";
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpContextUmbracoContextAccessor(IHttpContextAccessor httpContextAccessor)
public HttpContextUmbracoContextAccessor(IRequestCache requestCache)
{
_httpContextAccessor = httpContextAccessor;
_requestCache = requestCache;
}
public IUmbracoContext UmbracoContext
{
get
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) throw new Exception("oops:httpContext");
return (IUmbracoContext) httpContext.Items[HttpContextItemKey];
if (!_requestCache.IsAvailable) throw new InvalidOperationException("No request cache available");
return (IUmbracoContext) _requestCache.Get(HttpContextItemKey);
}
set
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) throw new Exception("oops:httpContext");
httpContext.Items[HttpContextItemKey] = value;
if (!_requestCache.IsAvailable) throw new InvalidOperationException("No request cache available");
_requestCache.Set(HttpContextItemKey, value);
}
}
}
@@ -1,4 +1,6 @@
namespace Umbraco.Web
using Umbraco.Core.Cache;
namespace Umbraco.Web
{
/// <summary>
/// Implements a hybrid <see cref="IUmbracoContextAccessor"/>.
@@ -8,8 +10,8 @@
/// <summary>
/// Initializes a new instance of the <see cref="HybridUmbracoContextAccessor"/> class.
/// </summary>
public HybridUmbracoContextAccessor(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
public HybridUmbracoContextAccessor(IRequestCache requestCache)
: base(requestCache)
{ }
/// <inheritdoc />
@@ -29,26 +29,24 @@ namespace Umbraco.Web.Install.InstallSteps
[InstallSetupStep(InstallationType.NewInstall, "User", 20, "")]
internal class NewInstallStep : InstallSetupStep<UserModel>
{
private readonly HttpContextBase _http;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserService _userService;
private readonly DatabaseBuilder _databaseBuilder;
private static HttpClient _httpClient;
private readonly IGlobalSettings _globalSettings;
private readonly IUserPasswordConfiguration _passwordConfiguration;
private readonly BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IConnectionStrings _connectionStrings;
public NewInstallStep(HttpContextBase http, IUserService userService, DatabaseBuilder databaseBuilder, IGlobalSettings globalSettings, IUserPasswordConfiguration passwordConfiguration, IUmbracoSettingsSection umbracoSettingsSection, IConnectionStrings connectionStrings)
public NewInstallStep(IHttpContextAccessor httpContextAccessor, IUserService userService, DatabaseBuilder databaseBuilder, IGlobalSettings globalSettings, IUserPasswordConfiguration passwordConfiguration, IUmbracoSettingsSection umbracoSettingsSection, IConnectionStrings connectionStrings)
{
_http = http;
_userService = userService;
_databaseBuilder = databaseBuilder;
_globalSettings = globalSettings;
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings));
_userManager = _http.GetOwinContext().GetBackOfficeUserManager();
}
public override async Task<InstallSetupResult> ExecuteAsync(UserModel user)
@@ -59,15 +57,16 @@ namespace Umbraco.Web.Install.InstallSteps
throw new InvalidOperationException("Could not find the super user!");
}
var membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserId);
var userManager = _httpContextAccessor.HttpContext.GetOwinContext().GetBackOfficeUserManager();
var membershipUser = await userManager.FindByIdAsync(Constants.Security.SuperUserId);
if (membershipUser == null)
{
throw new InvalidOperationException($"No user found in membership provider with id of {Constants.Security.SuperUserId}.");
}
//To change the password here we actually need to reset it since we don't have an old one to use to change
var resetToken = await _userManager.GeneratePasswordResetTokenAsync(membershipUser.Id);
var resetResult = await _userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, user.Password.Trim());
var resetToken = await userManager.GeneratePasswordResetTokenAsync(membershipUser.Id);
var resetResult = await userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, user.Password.Trim());
if (!resetResult.Succeeded)
{
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors));
@@ -138,7 +137,7 @@ namespace Umbraco.Web.Install.InstallSteps
// In this one case when it's a brand new install and nothing has been configured, make sure the
// back office cookie is cleared so there's no old cookies lying around causing problems
_http.ExpireCookie(_umbracoSettingsSection.Security.AuthCookieName);
_httpContextAccessor.HttpContext.ExpireCookie(_umbracoSettingsSection.Security.AuthCookieName);
return true;
}
@@ -18,16 +18,16 @@ namespace Umbraco.Web.Install.InstallSteps
PerformsAppRestart = true)]
internal class SetUmbracoVersionStep : InstallSetupStep<object>
{
private readonly HttpContextBase _httpContext;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly InstallHelper _installHelper;
private readonly IGlobalSettings _globalSettings;
private readonly IUserService _userService;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IIOHelper _ioHelper;
public SetUmbracoVersionStep(HttpContextBase httpContext, InstallHelper installHelper, IGlobalSettings globalSettings, IUserService userService, IUmbracoVersion umbracoVersion, IIOHelper ioHelper)
public SetUmbracoVersionStep(IHttpContextAccessor httpContextAccessor, InstallHelper installHelper, IGlobalSettings globalSettings, IUserService userService, IUmbracoVersion umbracoVersion, IIOHelper ioHelper)
{
_httpContext = httpContext;
_httpContextAccessor = httpContextAccessor;
_installHelper = installHelper;
_globalSettings = globalSettings;
_userService = userService;
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Install.InstallSteps
public override Task<InstallSetupResult> ExecuteAsync(object model)
{
var security = new WebSecurity(_httpContext, _userService, _globalSettings, _ioHelper);
var security = new WebSecurity(_httpContextAccessor.HttpContext, _userService, _globalSettings, _ioHelper);
if (security.IsAuthenticated() == false && _globalSettings.ConfigurationStatus.IsNullOrWhiteSpace())
{
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models.PublishedContent
{
@@ -7,8 +8,8 @@ namespace Umbraco.Web.Models.PublishedContent
/// </summary>
internal class HybridVariationContextAccessor : HybridAccessorBase<VariationContext>, IVariationContextAccessor
{
public HybridVariationContextAccessor(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
public HybridVariationContextAccessor(IRequestCache requestCache)
: base(requestCache)
{ }
/// <inheritdoc />
@@ -23,4 +24,4 @@ namespace Umbraco.Web.Models.PublishedContent
set => Value = value;
}
}
}
}
@@ -2,6 +2,8 @@
using System.Web.UI;
using ClientDependency.Core;
using ClientDependency.Core.CompositeFiles;
using Umbraco.Composing;
using Umbraco.Core.Hosting;
namespace Umbraco.Web.Mvc
{
@@ -13,6 +15,18 @@ namespace Umbraco.Web.Mvc
/// </remarks>
public class MinifyJavaScriptResultAttribute : ActionFilterAttribute
{
private readonly IHostingEnvironment _hostingEnvironment;
public MinifyJavaScriptResultAttribute()
{
_hostingEnvironment = Current.HostingEnvironment;
}
public MinifyJavaScriptResultAttribute(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
/// <summary>
/// Minify the result if in release mode
/// </summary>
@@ -24,7 +38,7 @@ namespace Umbraco.Web.Mvc
if (filterContext.Result == null) return;
var jsResult = filterContext.Result as JavaScriptResult;
if (jsResult == null) return;
if (filterContext.HttpContext.IsDebuggingEnabled) return;
if (_hostingEnvironment.IsDebugMode) return;
//minify the result
var result = jsResult.Script;
+1 -1
View File
@@ -33,7 +33,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Gets or sets the Umbraco context accessor.
/// </summary>
public virtual IUmbracoContextAccessor UmbracoContextAccessor { get; set; }
public IUmbracoContextAccessor UmbracoContextAccessor { get; set; }
/// <summary>
/// Gets or sets the services context.
@@ -72,7 +72,7 @@ namespace Umbraco.Web.Runtime
composition.Register<IFilePermissionHelper, FilePermissionHelper>(Lifetime.Singleton);
composition.RegisterUnique<IHttpContextAccessor, AspNetHttpContextAccessor>(); // required for hybrid accessors
composition.RegisterUnique<ICookieManager, AspNetCookieManager>();
composition.RegisterUnique<ICookieManager, AspNetCookieManager>();
composition.ComposeWebMappingProfiles();
@@ -89,7 +89,7 @@ namespace Umbraco.Web.Runtime
// register accessors for cultures
composition.RegisterUnique<IDefaultCultureAccessor, DefaultCultureAccessor>();
composition.RegisterUnique<IVariationContextAccessor, HybridVariationContextAccessor>();
// register the http context and umbraco context accessors
// we *should* use the HttpContextUmbracoContextAccessor, however there are cases when
@@ -11,6 +11,7 @@ using Microsoft.Owin.Security.DataHandler;
using Microsoft.Owin.Security.DataProtection;
using Owin;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -153,9 +154,10 @@ namespace Umbraco.Web.Security
IGlobalSettings globalSettings,
ISecuritySection securitySection,
IIOHelper ioHelper,
IRequestCache requestCache,
IUmbracoSettingsSection umbracoSettingsSection)
{
return app.UseUmbracoBackOfficeCookieAuthentication(umbracoContextAccessor, runtimeState, userService, globalSettings, securitySection, ioHelper, PipelineStage.Authenticate, umbracoSettingsSection);
return app.UseUmbracoBackOfficeCookieAuthentication(umbracoContextAccessor, runtimeState, userService, globalSettings, securitySection, ioHelper, requestCache, PipelineStage.Authenticate, umbracoSettingsSection);
}
/// <summary>
@@ -179,11 +181,12 @@ namespace Umbraco.Web.Security
IGlobalSettings globalSettings,
ISecuritySection securitySection,
IIOHelper ioHelper,
IRequestCache requestCache,
PipelineStage stage,
IUmbracoSettingsSection umbracoSettingsSection)
{
//Create the default options and provider
var authOptions = app.CreateUmbracoCookieAuthOptions(umbracoContextAccessor, globalSettings, runtimeState, securitySection, ioHelper);
var authOptions = app.CreateUmbracoCookieAuthOptions(umbracoContextAccessor, globalSettings, runtimeState, securitySection, ioHelper, requestCache);
authOptions.Provider = new BackOfficeCookieAuthenticationProvider(userService, runtimeState, globalSettings, ioHelper, umbracoSettingsSection)
{
@@ -198,7 +201,7 @@ namespace Umbraco.Web.Security
};
return app.UseUmbracoBackOfficeCookieAuthentication(umbracoContextAccessor, runtimeState, globalSettings, securitySection, ioHelper, authOptions, stage);
return app.UseUmbracoBackOfficeCookieAuthentication(umbracoContextAccessor, runtimeState, globalSettings, securitySection, ioHelper, requestCache, authOptions, stage);
}
/// <summary>
@@ -215,7 +218,8 @@ namespace Umbraco.Web.Security
/// Configurable pipeline stage
/// </param>
/// <returns></returns>
public static IAppBuilder UseUmbracoBackOfficeCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings, ISecuritySection securitySection, IIOHelper ioHelper, CookieAuthenticationOptions cookieOptions, PipelineStage stage)
public static IAppBuilder UseUmbracoBackOfficeCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings,
ISecuritySection securitySection, IIOHelper ioHelper, IRequestCache requestCache, CookieAuthenticationOptions cookieOptions, PipelineStage stage)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState));
@@ -225,7 +229,7 @@ namespace Umbraco.Web.Security
if (cookieOptions.Provider is BackOfficeCookieAuthenticationProvider == false)
throw new ArgumentException($"cookieOptions.Provider must be of type {typeof(BackOfficeCookieAuthenticationProvider)}.", nameof(cookieOptions));
app.UseUmbracoBackOfficeCookieAuthenticationInternal(cookieOptions, runtimeState, stage);
app.UseUmbracoBackOfficeCookieAuthenticationInternal(cookieOptions, runtimeState, requestCache, stage);
//don't apply if app is not ready
if (runtimeState.Level != RuntimeLevel.Upgrade && runtimeState.Level != RuntimeLevel.Run) return app;
@@ -233,7 +237,7 @@ namespace Umbraco.Web.Security
var cookieAuthOptions = app.CreateUmbracoCookieAuthOptions(
umbracoContextAccessor, globalSettings, runtimeState, securitySection,
//This defines the explicit path read cookies from for this middleware
ioHelper, new[] {$"{globalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds"});
ioHelper, requestCache, new[] {$"{globalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds"});
cookieAuthOptions.Provider = cookieOptions.Provider;
//This is a custom middleware, we need to return the user's remaining logged in seconds
@@ -279,7 +283,7 @@ namespace Umbraco.Web.Security
});
}
private static void UseUmbracoBackOfficeCookieAuthenticationInternal(this IAppBuilder app, CookieAuthenticationOptions options, IRuntimeState runtimeState, PipelineStage stage)
private static void UseUmbracoBackOfficeCookieAuthenticationInternal(this IAppBuilder app, CookieAuthenticationOptions options, IRuntimeState runtimeState, IRequestCache requestCache, PipelineStage stage)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState));
@@ -290,7 +294,7 @@ namespace Umbraco.Web.Security
if (runtimeState.Level == RuntimeLevel.Upgrade || runtimeState.Level == RuntimeLevel.Run)
{
//Then our custom middlewares
app.Use(typeof(ForceRenewalCookieAuthenticationMiddleware), app, options, Current.UmbracoContextAccessor);
app.Use(typeof(ForceRenewalCookieAuthenticationMiddleware), app, options, Current.UmbracoContextAccessor, requestCache);
app.Use(typeof(FixWindowsAuthMiddlware));
}
@@ -311,9 +315,9 @@ namespace Umbraco.Web.Security
/// <remarks>
/// By default this will be configured to execute on PipelineStage.Authenticate
/// </remarks>
public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState,IGlobalSettings globalSettings, IIOHelper ioHelper)
public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState,IGlobalSettings globalSettings, IIOHelper ioHelper, IRequestCache requestCache)
{
return app.UseUmbracoBackOfficeExternalCookieAuthentication(umbracoContextAccessor, runtimeState, globalSettings, ioHelper, PipelineStage.Authenticate);
return app.UseUmbracoBackOfficeExternalCookieAuthentication(umbracoContextAccessor, runtimeState, globalSettings, ioHelper, requestCache, PipelineStage.Authenticate);
}
/// <summary>
@@ -329,7 +333,7 @@ namespace Umbraco.Web.Security
/// <returns></returns>
public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app,
IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState,
IGlobalSettings globalSettings, IIOHelper ioHelper, PipelineStage stage)
IGlobalSettings globalSettings, IIOHelper ioHelper, IRequestCache requestCache, PipelineStage stage)
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState));
@@ -342,7 +346,7 @@ namespace Umbraco.Web.Security
CookieName = Constants.Security.BackOfficeExternalCookieName,
ExpireTimeSpan = TimeSpan.FromMinutes(5),
//Custom cookie manager so we can filter requests
CookieManager = new BackOfficeCookieManager(umbracoContextAccessor, runtimeState, globalSettings, ioHelper),
CookieManager = new BackOfficeCookieManager(umbracoContextAccessor, runtimeState, globalSettings, ioHelper, requestCache),
CookiePath = "/",
CookieSecure = globalSettings.UseHttps ? CookieSecureOption.Always : CookieSecureOption.SameAsRequest,
CookieHttpOnly = true,
@@ -369,9 +373,9 @@ namespace Umbraco.Web.Security
/// <remarks>
/// By default this will be configured to execute on PipelineStage.PostAuthenticate
/// </remarks>
public static IAppBuilder UseUmbracoPreviewAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings, ISecuritySection securitySettings, IIOHelper ioHelper)
public static IAppBuilder UseUmbracoPreviewAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings, ISecuritySection securitySettings, IIOHelper ioHelper, IRequestCache requestCache)
{
return app.UseUmbracoPreviewAuthentication(umbracoContextAccessor, runtimeState, globalSettings, securitySettings, ioHelper, PipelineStage.PostAuthenticate);
return app.UseUmbracoPreviewAuthentication(umbracoContextAccessor, runtimeState, globalSettings, securitySettings, ioHelper, requestCache, PipelineStage.PostAuthenticate);
}
/// <summary>
@@ -389,11 +393,11 @@ namespace Umbraco.Web.Security
/// This ensures that during a preview request that the back office use is also Authenticated and that the back office Identity
/// is added as a secondary identity to the current IPrincipal so it can be used to Authorize the previewed document.
/// </remarks>
public static IAppBuilder UseUmbracoPreviewAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings, ISecuritySection securitySettings, IIOHelper ioHelper, PipelineStage stage)
public static IAppBuilder UseUmbracoPreviewAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, IGlobalSettings globalSettings, ISecuritySection securitySettings, IIOHelper ioHelper, IRequestCache requestCache, PipelineStage stage)
{
if (runtimeState.Level != RuntimeLevel.Run) return app;
var authOptions = app.CreateUmbracoCookieAuthOptions(umbracoContextAccessor, globalSettings, runtimeState, securitySettings, ioHelper);
var authOptions = app.CreateUmbracoCookieAuthOptions(umbracoContextAccessor, globalSettings, runtimeState, securitySettings, ioHelper, requestCache);
app.Use(typeof(PreviewAuthenticationMiddleware), authOptions, Current.Configs.Global(), ioHelper);
// This middleware must execute at least on PostAuthentication, by default it is on Authorize
@@ -424,7 +428,7 @@ namespace Umbraco.Web.Security
/// <returns></returns>
public static UmbracoBackOfficeCookieAuthOptions CreateUmbracoCookieAuthOptions(this IAppBuilder app,
IUmbracoContextAccessor umbracoContextAccessor,
IGlobalSettings globalSettings, IRuntimeState runtimeState, ISecuritySection securitySettings, IIOHelper ioHelper, string[] explicitPaths = null)
IGlobalSettings globalSettings, IRuntimeState runtimeState, ISecuritySection securitySettings, IIOHelper ioHelper, IRequestCache requestCache, string[] explicitPaths = null)
{
//this is how aspnet wires up the default AuthenticationTicket protector so we'll use the same code
var ticketDataFormat = new TicketDataFormat(
@@ -439,7 +443,8 @@ namespace Umbraco.Web.Security
globalSettings,
runtimeState,
ticketDataFormat,
ioHelper);
ioHelper,
requestCache);
return authOptions;
}
@@ -169,18 +169,6 @@ namespace Umbraco.Web.Security
return true;
}
/// <summary>
/// This will force ticket renewal in the OWIN pipeline
/// </summary>
/// <param name="http"></param>
/// <returns></returns>
internal static bool RenewUmbracoAuthTicket(this HttpContext http)
{
if (http == null) throw new ArgumentNullException("http");
http.Items[Constants.Security.ForceReAuthFlag] = true;
return true;
}
/// <summary>
/// returns the number of seconds the user has until their auth session times out
/// </summary>
@@ -5,6 +5,7 @@ using System.Web;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Security;
@@ -24,19 +25,21 @@ namespace Umbraco.Web.Security
private readonly IRuntimeState _runtime;
private readonly IGlobalSettings _globalSettings;
private readonly IIOHelper _ioHelper;
private readonly IRequestCache _requestCache;
private readonly string[] _explicitPaths;
private readonly string _getRemainingSecondsPath;
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IGlobalSettings globalSettings, IIOHelper ioHelper)
: this(umbracoContextAccessor, runtime, globalSettings, ioHelper,null)
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IGlobalSettings globalSettings, IIOHelper ioHelper, IRequestCache requestCache)
: this(umbracoContextAccessor, runtime, globalSettings, ioHelper,requestCache, null)
{ }
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IGlobalSettings globalSettings, IIOHelper ioHelper, IEnumerable<string> explicitPaths)
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IGlobalSettings globalSettings, IIOHelper ioHelper, IRequestCache requestCache, IEnumerable<string> explicitPaths)
{
_umbracoContextAccessor = umbracoContextAccessor;
_runtime = runtime;
_globalSettings = globalSettings;
_ioHelper = ioHelper;
_requestCache = requestCache;
_explicitPaths = explicitPaths?.ToArray();
_getRemainingSecondsPath = $"{globalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds";
}
@@ -89,8 +92,6 @@ namespace Umbraco.Web.Security
return false;
var request = owinContext.Request;
var httpContext = owinContext.TryGetHttpContext();
//check the explicit paths
if (_explicitPaths != null)
{
@@ -102,7 +103,7 @@ namespace Umbraco.Web.Security
if (//check the explicit flag
(checkForceAuthTokens && owinContext.Get<bool?>(Constants.Security.ForceReAuthFlag) != null)
|| (checkForceAuthTokens && httpContext.Success && httpContext.Result.Items[Constants.Security.ForceReAuthFlag] != null)
|| (checkForceAuthTokens && _requestCache.IsAvailable && _requestCache.Get(Constants.Security.ForceReAuthFlag) != null)
//check back office
|| request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath, _globalSettings, _ioHelper)
//check installer
@@ -3,6 +3,7 @@ using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Infrastructure;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Security;
namespace Umbraco.Web.Security
@@ -13,10 +14,12 @@ namespace Umbraco.Web.Security
internal class ForceRenewalCookieAuthenticationHandler : AuthenticationHandler<CookieAuthenticationOptions>
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IRequestCache _requestCache;
public ForceRenewalCookieAuthenticationHandler(IUmbracoContextAccessor umbracoContextAccessor)
public ForceRenewalCookieAuthenticationHandler(IUmbracoContextAccessor umbracoContextAccessor, IRequestCache requestCache)
{
_umbracoContextAccessor = umbracoContextAccessor;
_requestCache = requestCache;
}
/// <summary>
@@ -68,9 +71,8 @@ namespace Umbraco.Web.Security
//This is auth'd normally, so OWIN will naturally take care of the cookie renewal
if (normalAuthUrl) return Task.FromResult(0);
var httpCtx = Context.TryGetHttpContext();
//check for the special flag in either the owin or http context
var shouldRenew = Context.Get<bool?>(Constants.Security.ForceReAuthFlag) != null || (httpCtx.Success && httpCtx.Result.Items[Constants.Security.ForceReAuthFlag] != null);
var shouldRenew = Context.Get<bool?>(Constants.Security.ForceReAuthFlag) != null || (_requestCache.IsAvailable && _requestCache.Get(Constants.Security.ForceReAuthFlag) != null);
if (shouldRenew)
{
@@ -2,6 +2,7 @@
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Infrastructure;
using Owin;
using Umbraco.Core.Cache;
namespace Umbraco.Web.Security
{
@@ -11,19 +12,22 @@ namespace Umbraco.Web.Security
internal class ForceRenewalCookieAuthenticationMiddleware : CookieAuthenticationMiddleware
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IRequestCache _requestCache;
public ForceRenewalCookieAuthenticationMiddleware(
OwinMiddleware next,
IAppBuilder app,
UmbracoBackOfficeCookieAuthOptions options,
IUmbracoContextAccessor umbracoContextAccessor) : base(next, app, options)
IUmbracoContextAccessor umbracoContextAccessor,
IRequestCache requestCache) : base(next, app, options)
{
_umbracoContextAccessor = umbracoContextAccessor;
_requestCache = requestCache;
}
protected override AuthenticationHandler<CookieAuthenticationOptions> CreateHandler()
{
return new ForceRenewalCookieAuthenticationHandler(_umbracoContextAccessor);
return new ForceRenewalCookieAuthenticationHandler(_umbracoContextAccessor, _requestCache);
}
}
}
@@ -3,6 +3,7 @@ using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -23,7 +24,8 @@ namespace Umbraco.Web.Security
IGlobalSettings globalSettings,
IRuntimeState runtimeState,
ISecureDataFormat<AuthenticationTicket> secureDataFormat,
IIOHelper ioHelper)
IIOHelper ioHelper,
IRequestCache requestCache)
{
var secureDataFormat1 = secureDataFormat ?? throw new ArgumentNullException(nameof(secureDataFormat));
LoginTimeoutMinutes = globalSettings.TimeOutInMinutes;
@@ -40,7 +42,7 @@ namespace Umbraco.Web.Security
TicketDataFormat = new UmbracoSecureDataFormat(LoginTimeoutMinutes, secureDataFormat1);
//Custom cookie manager so we can filter requests
CookieManager = new BackOfficeCookieManager(umbracoContextAccessor, runtimeState, globalSettings, ioHelper, explicitPaths);
CookieManager = new BackOfficeCookieManager(umbracoContextAccessor, runtimeState, globalSettings, ioHelper, requestCache, explicitPaths);
}
/// <summary>
+3 -13
View File
@@ -173,7 +173,6 @@
<Compile Include="Models\Identity\IdentityMapDefinition.cs" />
<Compile Include="Models\Identity\IdentityUser.cs" />
<Compile Include="Models\Identity\UserLoginInfoWrapper.cs" />
<Compile Include="Models\ImageProcessorImageUrlGenerator.cs" />
<Compile Include="Models\Mapping\CommonMapper.cs" />
<Compile Include="Models\Mapping\ContentMapDefinition.cs" />
<Compile Include="Models\Mapping\ContentPropertyBasicMapper.cs" />
@@ -190,9 +189,11 @@
<Compile Include="Models\Mapping\TabsAndPropertiesMapper.cs" />
<Compile Include="Models\Mapping\UserMapDefinition.cs" />
<Compile Include="Models\Membership\UmbracoMembershipMember.cs" />
<Compile Include="Models\PublishedContent\HybridVariationContextAccessor.cs" />
<Compile Include="Models\Trees\MenuItemCollection.cs" />
<Compile Include="Models\Trees\MenuItemList.cs" />
<Compile Include="Models\Trees\TreeNodeCollection.cs" />
<Compile Include="Models\Trees\TreeNodeExtensions.cs" />
<Compile Include="Models\Trees\TreeRootNode.cs" />
<Compile Include="Mvc\HttpUmbracoFormRouteStringException.cs" />
<Compile Include="Mvc\ModelBindingExceptionFilter.cs" />
<Compile Include="Mvc\StatusCodeFilterAttribute.cs" />
@@ -308,10 +309,8 @@
<Compile Include="Features\DisabledFeatures.cs" />
<Compile Include="Features\EnabledFeatures.cs" />
<Compile Include="Features\UmbracoFeatures.cs" />
<Compile Include="HybridAccessorBase.cs" />
<Compile Include="HybridUmbracoContextAccessor.cs" />
<Compile Include="HttpContextUmbracoContextAccessor.cs" />
<Compile Include="HybridEventMessagesAccessor.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Composing\CompositionExtensions\WebMappingProfiles.cs" />
<Compile Include="Editors\BackOfficeNotificationsController.cs" />
@@ -329,10 +328,6 @@
<Compile Include="Editors\IEditorValidator.cs" />
<Compile Include="Editors\EditorModelEventManager.cs" />
<Compile Include="HtmlHelperBackOfficeExtensions.cs" />
<Compile Include="Models\ContentTypeImportModel.cs" />
<Compile Include="Models\PublishedContent\HttpContextVariationContextAccessor.cs" />
<Compile Include="Models\PublishedContent\PublishedValueFallback.cs" />
<Compile Include="Models\Trees\ExportMember.cs" />
<Compile Include="Composing\ModuleInjector.cs" />
<Compile Include="Mvc\FilteredControllerFactoryCollection.cs" />
<Compile Include="Mvc\FilteredControllerFactoryCollectionBuilder.cs" />
@@ -381,7 +376,6 @@
<Compile Include="Editors\PublishedSnapshotCacheStatusController.cs" />
<Compile Include="Trees\TreeAttribute.cs" />
<Compile Include="Routing\NotFoundHandlerHelper.cs" />
<Compile Include="Models\LocalPackageInstallModel.cs" />
<Compile Include="Mvc\ControllerContextExtensions.cs" />
<Compile Include="Mvc\DisableBrowserCacheAttribute.cs" />
<Compile Include="Mvc\EnsurePartialViewMacroViewContextFilterAttribute.cs" />
@@ -496,7 +490,6 @@
<Compile Include="Trees\LanguageTreeController.cs" />
<Compile Include="Trees\MemberTreeController.cs" />
<Compile Include="Trees\MenuRenderingEventArgs.cs" />
<Compile Include="Models\Trees\CreateChildEntity.cs" />
<Compile Include="Trees\TemplatesTreeController.cs" />
<Compile Include="Trees\TreeControllerBase.cs" />
<Compile Include="JavaScript\AssetInitialization.cs" />
@@ -538,10 +531,7 @@
<Compile Include="FormDataCollectionExtensions.cs" />
<Compile Include="Trees\MediaTreeController.cs" />
<Compile Include="Trees\ContentTreeControllerBase.cs" />
<Compile Include="Models\Trees\TreeRootNode.cs" />
<Compile Include="Trees\TreeController.cs" />
<Compile Include="Models\Trees\TreeNodeCollection.cs" />
<Compile Include="Models\Trees\TreeNodeExtensions.cs" />
<Compile Include="Trees\TreeNodeRenderingEventArgs.cs" />
<Compile Include="Trees\TreeNodesRenderingEventArgs.cs" />
<Compile Include="Trees\TreeQueryStringParameters.cs" />
+5 -3
View File
@@ -2,6 +2,7 @@
using Microsoft.Owin;
using Owin;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -34,6 +35,7 @@ namespace Umbraco.Web
protected UmbracoMapper Mapper => Current.Mapper;
protected IIpResolver IpResolver => Current.IpResolver;
protected IIOHelper IOHelper => Current.IOHelper;
protected IRequestCache RequestCache => Current.AppCaches.RequestCache;
/// <summary>
/// Main startup method
@@ -102,9 +104,9 @@ namespace Umbraco.Web
// Ensure owin is configured for Umbraco back office authentication.
// Front-end OWIN cookie configuration must be declared after this code.
app
.UseUmbracoBackOfficeCookieAuthentication(UmbracoContextAccessor, RuntimeState, Services.UserService, GlobalSettings, UmbracoSettings.Security, IOHelper, PipelineStage.Authenticate, UmbracoSettings)
.UseUmbracoBackOfficeExternalCookieAuthentication(UmbracoContextAccessor, RuntimeState, GlobalSettings, IOHelper, PipelineStage.Authenticate)
.UseUmbracoPreviewAuthentication(UmbracoContextAccessor, RuntimeState, GlobalSettings, UmbracoSettings.Security, IOHelper, PipelineStage.Authorize);
.UseUmbracoBackOfficeCookieAuthentication(UmbracoContextAccessor, RuntimeState, Services.UserService, GlobalSettings, UmbracoSettings.Security, IOHelper, RequestCache, PipelineStage.Authenticate, UmbracoSettings)
.UseUmbracoBackOfficeExternalCookieAuthentication(UmbracoContextAccessor, RuntimeState, GlobalSettings, IOHelper, RequestCache, PipelineStage.Authenticate)
.UseUmbracoPreviewAuthentication(UmbracoContextAccessor, RuntimeState, GlobalSettings, UmbracoSettings.Security, IOHelper, RequestCache, PipelineStage.Authorize);
}
public static event EventHandler<OwinMiddlewareConfiguredEventArgs> MiddlewareConfigured;
+12 -8
View File
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Web;
using System.Web.Routing;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -38,6 +39,7 @@ namespace Umbraco.Web
private readonly IPublishedRouter _publishedRouter;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly RoutableDocumentFilter _routableDocumentLookup;
private readonly IRequestCache _requestCache;
public UmbracoInjectedModule(
IGlobalSettings globalSettings,
@@ -45,7 +47,8 @@ namespace Umbraco.Web
ILogger logger,
IPublishedRouter publishedRouter,
IUmbracoContextFactory umbracoContextFactory,
RoutableDocumentFilter routableDocumentLookup)
RoutableDocumentFilter routableDocumentLookup,
IRequestCache requestCache)
{
_globalSettings = globalSettings;
_runtime = runtime;
@@ -53,6 +56,7 @@ namespace Umbraco.Web
_publishedRouter = publishedRouter;
_umbracoContextFactory = umbracoContextFactory;
_routableDocumentLookup = routableDocumentLookup;
_requestCache = requestCache;
}
#region HttpModule event handlers
@@ -305,15 +309,15 @@ namespace Umbraco.Web
/// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
/// </summary>
/// <param name="http"></param>
private void DisposeHttpContextItems(HttpContext http)
private void DisposeRequestCacheItems(HttpContext http, IRequestCache requestCache)
{
// do not process if client-side request
if (http.Request.Url.IsClientSideRequest())
return;
//get a list of keys to dispose
var keys = new HashSet<object>();
foreach (DictionaryEntry i in http.Items)
var keys = new HashSet<string>();
foreach (var i in requestCache)
{
if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd)
{
@@ -325,7 +329,7 @@ namespace Umbraco.Web
{
try
{
http.Items[k].DisposeIfDisposable();
requestCache.Get(k).DisposeIfDisposable();
}
catch (Exception ex)
{
@@ -376,7 +380,7 @@ namespace Umbraco.Web
{
var httpContext = ((HttpApplication) sender).Context;
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, Current.AppCaches.RequestCache);
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache);
_logger.Verbose<UmbracoModule>("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, httpContext.Request.Url);
BeginRequest(new HttpContextWrapper(httpContext));
@@ -421,14 +425,14 @@ namespace Umbraco.Web
if (Current.UmbracoContext != null && Current.UmbracoContext.IsFrontEndUmbracoRequest)
{
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, Current.AppCaches.RequestCache);
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache);
_logger.Verbose<UmbracoModule>("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, httpContext.Request.Url, DateTime.Now.Subtract(Current.UmbracoContext.ObjectCreated).TotalMilliseconds);
}
UmbracoModule.OnEndRequest(this, new UmbracoRequestEventArgs(Current.UmbracoContext, new HttpContextWrapper(httpContext)));
DisposeHttpContextItems(httpContext);
DisposeRequestCacheItems(httpContext, _requestCache);
};
}