Moved compoenents and composers
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
using System;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Core.Request
|
||||
{
|
||||
public interface IRequestAccessor
|
||||
{
|
||||
string GetRequestValue(string name);
|
||||
string GetQueryStringValue(string culture);
|
||||
event EventHandler<UmbracoRequestEventArgs> EndRequest;
|
||||
event EventHandler<RoutableAttemptEventArgs> RouteAttempt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ namespace Umbraco.Core.Sync
|
||||
/// <summary>
|
||||
/// An <see cref="IServerMessenger"/> implementation that works by storing messages in the database.
|
||||
/// </summary>
|
||||
public interface IBatchedDatabaseServerMessenger : IServerMessenger
|
||||
public interface IBatchedDatabaseServerMessenger : IDatabaseServerMessenger
|
||||
{
|
||||
void FlushBatch();
|
||||
DatabaseServerMessengerOptions Options { get; }
|
||||
void Startup();
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs
Normal file
7
src/Umbraco.Core/Sync/IDatabaseServerMessenger.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
public interface IDatabaseServerMessenger: IServerMessenger
|
||||
{
|
||||
void Sync();
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Web.Composing;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Request;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
@@ -29,19 +25,30 @@ namespace Umbraco.Web
|
||||
{
|
||||
private readonly IUmbracoDatabaseFactory _databaseFactory;
|
||||
private readonly IRequestCache _requestCache;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
|
||||
public BatchedDatabaseServerMessenger(
|
||||
IRuntimeState runtime, IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IRequestCache requestCache)
|
||||
IRuntimeState runtime,
|
||||
IUmbracoDatabaseFactory databaseFactory,
|
||||
IScopeProvider scopeProvider,
|
||||
ISqlContext sqlContext,
|
||||
IProfilingLogger proflog,
|
||||
DatabaseServerMessengerOptions options,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
CacheRefresherCollection cacheRefreshers,
|
||||
IRequestCache requestCache,
|
||||
IRequestAccessor requestAccessor)
|
||||
: base(runtime, scopeProvider, sqlContext, proflog, true, options, hostingEnvironment, cacheRefreshers)
|
||||
{
|
||||
_databaseFactory = databaseFactory;
|
||||
_requestCache = requestCache;
|
||||
_requestAccessor = requestAccessor;
|
||||
}
|
||||
|
||||
// invoked by DatabaseServerRegistrarAndMessengerComponent
|
||||
internal void Startup()
|
||||
public void Startup()
|
||||
{
|
||||
UmbracoModule.EndRequest += UmbracoModule_EndRequest;
|
||||
_requestAccessor.EndRequest += UmbracoModule_EndRequest;
|
||||
|
||||
if (_databaseFactory.CanConnect == false)
|
||||
{
|
||||
@@ -104,7 +111,7 @@ namespace Umbraco.Web
|
||||
|
||||
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
||||
{
|
||||
var key = typeof (BatchedDatabaseServerMessenger).Name;
|
||||
var key = nameof(BatchedDatabaseServerMessenger);
|
||||
|
||||
if (!_requestCache.IsAvailable) return null;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Request;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Changes;
|
||||
using Umbraco.Core.Sync;
|
||||
@@ -82,7 +83,7 @@ namespace Umbraco.Web.Compose
|
||||
{
|
||||
private object _locker = new object();
|
||||
private readonly DatabaseServerRegistrar _registrar;
|
||||
private readonly BatchedDatabaseServerMessenger _messenger;
|
||||
private readonly IBatchedDatabaseServerMessenger _messenger;
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerRegistrationService _registrationService;
|
||||
@@ -91,13 +92,23 @@ namespace Umbraco.Web.Compose
|
||||
private bool _started;
|
||||
private IBackgroundTask[] _tasks;
|
||||
private IndexRebuilder _indexRebuilder;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
|
||||
public DatabaseServerRegistrarAndMessengerComponent(IRuntimeState runtime, IServerRegistrar serverRegistrar, IServerMessenger serverMessenger, IServerRegistrationService registrationService, ILogger logger, IHostingEnvironment hostingEnvironment, IndexRebuilder indexRebuilder)
|
||||
public DatabaseServerRegistrarAndMessengerComponent(
|
||||
IRuntimeState runtime,
|
||||
IServerRegistrar serverRegistrar,
|
||||
IServerMessenger serverMessenger,
|
||||
IServerRegistrationService registrationService,
|
||||
ILogger logger,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IndexRebuilder indexRebuilder,
|
||||
IRequestAccessor requestAccessor)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_logger = logger;
|
||||
_registrationService = registrationService;
|
||||
_indexRebuilder = indexRebuilder;
|
||||
_requestAccessor = requestAccessor;
|
||||
|
||||
// create task runner for DatabaseServerRegistrar
|
||||
_registrar = serverRegistrar as DatabaseServerRegistrar;
|
||||
@@ -108,7 +119,7 @@ namespace Umbraco.Web.Compose
|
||||
}
|
||||
|
||||
// create task runner for BatchedDatabaseServerMessenger
|
||||
_messenger = serverMessenger as BatchedDatabaseServerMessenger;
|
||||
_messenger = serverMessenger as IBatchedDatabaseServerMessenger;
|
||||
if (_messenger != null)
|
||||
{
|
||||
_processTaskRunner = new BackgroundTaskRunner<IBackgroundTask>("ServerInstProcess",
|
||||
@@ -120,7 +131,7 @@ namespace Umbraco.Web.Compose
|
||||
{
|
||||
//We will start the whole process when a successful request is made
|
||||
if (_registrar != null || _messenger != null)
|
||||
UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
_requestAccessor.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
|
||||
// must come last, as it references some _variables
|
||||
_messenger?.Startup();
|
||||
@@ -137,7 +148,7 @@ namespace Umbraco.Web.Compose
|
||||
/// <remarks>
|
||||
/// We require this because:
|
||||
/// - ApplicationContext.UmbracoApplicationUrl is initialized by UmbracoModule in BeginRequest
|
||||
/// - RegisterServer is called on UmbracoModule.RouteAttempt which is triggered in ProcessRequest
|
||||
/// - RegisterServer is called on _requestAccessor.RouteAttempt which is triggered in ProcessRequest
|
||||
/// we are safe, UmbracoApplicationUrl has been initialized
|
||||
/// </remarks>
|
||||
private void RegisterBackgroundTasksOnce(object sender, RoutableAttemptEventArgs e)
|
||||
@@ -146,7 +157,7 @@ namespace Umbraco.Web.Compose
|
||||
{
|
||||
case EnsureRoutableOutcome.IsRoutable:
|
||||
case EnsureRoutableOutcome.NotDocumentRequest:
|
||||
UmbracoModule.RouteAttempt -= RegisterBackgroundTasksOnce;
|
||||
_requestAccessor.RouteAttempt -= RegisterBackgroundTasksOnce;
|
||||
RegisterBackgroundTasks();
|
||||
break;
|
||||
}
|
||||
@@ -196,11 +207,11 @@ namespace Umbraco.Web.Compose
|
||||
|
||||
private class InstructionProcessTask : RecurringTaskBase
|
||||
{
|
||||
private readonly DatabaseServerMessenger _messenger;
|
||||
private readonly IDatabaseServerMessenger _messenger;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public InstructionProcessTask(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
|
||||
DatabaseServerMessenger messenger, ILogger logger)
|
||||
IDatabaseServerMessenger messenger, ILogger logger)
|
||||
: base(runner, delayMilliseconds, periodMilliseconds)
|
||||
{
|
||||
_messenger = messenger;
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Request;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
@@ -37,6 +38,7 @@ namespace Umbraco.Web.Scheduling
|
||||
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
|
||||
private readonly IIOHelper _ioHelper;
|
||||
private readonly IServerMessenger _serverMessenger;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
|
||||
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
|
||||
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
|
||||
@@ -54,7 +56,7 @@ namespace Umbraco.Web.Scheduling
|
||||
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
|
||||
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger,
|
||||
IHostingEnvironment hostingEnvironment, IHealthChecks healthChecksConfig,
|
||||
IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IServerMessenger serverMessenger)
|
||||
IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IServerMessenger serverMessenger, IRequestAccessor requestAccessor)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_contentService = contentService;
|
||||
@@ -70,6 +72,7 @@ namespace Umbraco.Web.Scheduling
|
||||
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
|
||||
_ioHelper = ioHelper;
|
||||
_serverMessenger = serverMessenger;
|
||||
_requestAccessor = requestAccessor;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -83,7 +86,7 @@ namespace Umbraco.Web.Scheduling
|
||||
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("HealthCheckNotifier", _logger, _hostingEnvironment);
|
||||
|
||||
// we will start the whole process when a successful request is made
|
||||
UmbracoModule.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
_requestAccessor.RouteAttempt += RegisterBackgroundTasksOnce;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
@@ -97,7 +100,6 @@ namespace Umbraco.Web.Scheduling
|
||||
{
|
||||
case EnsureRoutableOutcome.IsRoutable:
|
||||
case EnsureRoutableOutcome.NotDocumentRequest:
|
||||
UmbracoModule.RouteAttempt -= RegisterBackgroundTasksOnce;
|
||||
RegisterBackgroundTasks();
|
||||
break;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Sync
|
||||
// but only processes instructions coming from remote servers,
|
||||
// thus ensuring that instructions run only once
|
||||
//
|
||||
public class DatabaseServerMessenger : ServerMessengerBase
|
||||
public class DatabaseServerMessenger : ServerMessengerBase, IDatabaseServerMessenger
|
||||
{
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly ManualResetEvent _syncIdle;
|
||||
@@ -126,10 +126,6 @@ namespace Umbraco.Core.Sync
|
||||
const int weight = 10;
|
||||
|
||||
|
||||
//TODO Why do we have interface if we expect to be exact type!!!?
|
||||
// if (!(_runtime is RuntimeState runtime))
|
||||
// throw new NotSupportedException($"Unsupported IRuntimeState implementation {_runtime.GetType().FullName}, expecting {typeof(RuntimeState).FullName}.");
|
||||
|
||||
var registered = _runtime.MainDom.Register(
|
||||
() =>
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Composing;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
@@ -20,14 +21,17 @@ namespace Umbraco.Tests.Cache
|
||||
public class DeepCloneAppCacheTests : RuntimeAppCacheTests
|
||||
{
|
||||
private DeepCloneAppCache _provider;
|
||||
private ObjectCacheAppCache _memberCache;
|
||||
|
||||
protected override int GetTotalItemCount => HttpRuntime.Cache.Count;
|
||||
protected override int GetTotalItemCount => _memberCache.MemoryCache.Count();
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_provider = new DeepCloneAppCache(new WebCachingAppCache(HttpRuntime.Cache, typeFinder));
|
||||
_memberCache = new ObjectCacheAppCache(typeFinder);
|
||||
|
||||
_provider = new DeepCloneAppCache(_memberCache);
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache => _provider;
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Cache;
|
||||
|
||||
namespace Umbraco.Tests.Cache
|
||||
{
|
||||
[TestFixture]
|
||||
public class WebCachingAppCacheTests : RuntimeAppCacheTests
|
||||
{
|
||||
private WebCachingAppCache _appCache;
|
||||
|
||||
protected override int GetTotalItemCount => HttpRuntime.Cache.Count;
|
||||
|
||||
public override void Setup()
|
||||
{
|
||||
base.Setup();
|
||||
var typeFinder = new TypeFinder(Mock.Of<ILogger>());
|
||||
_appCache = new WebCachingAppCache(HttpRuntime.Cache, typeFinder);
|
||||
}
|
||||
|
||||
internal override IAppCache AppCache => _appCache;
|
||||
|
||||
internal override IAppPolicyCache AppPolicyCache => _appCache;
|
||||
|
||||
[Test]
|
||||
public void DoesNotCacheExceptions()
|
||||
{
|
||||
string value;
|
||||
Assert.Throws<Exception>(() => { value = (string)_appCache.Get("key", () => GetValue(1)); });
|
||||
Assert.Throws<Exception>(() => { value = (string)_appCache.Get("key", () => GetValue(2)); });
|
||||
|
||||
// does not throw
|
||||
value = (string)_appCache.Get("key", () => GetValue(3));
|
||||
Assert.AreEqual("succ3", value);
|
||||
|
||||
// cache
|
||||
value = (string)_appCache.Get("key", () => GetValue(4));
|
||||
Assert.AreEqual("succ3", value);
|
||||
}
|
||||
|
||||
private static string GetValue(int i)
|
||||
{
|
||||
Debug.Print("get" + i);
|
||||
if (i < 3)
|
||||
throw new Exception("fail");
|
||||
return "succ" + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,6 @@
|
||||
<Compile Include="Cache\ObjectAppCacheTests.cs" />
|
||||
<Compile Include="Cache\AppCacheTests.cs" />
|
||||
<Compile Include="Cache\HttpRequestAppCacheTests.cs" />
|
||||
<Compile Include="Cache\WebCachingAppCacheTests.cs" />
|
||||
<Compile Include="Cache\RuntimeAppCacheTests.cs" />
|
||||
<Compile Include="Configurations\UmbracoSettings\ContentElementDefaultTests.cs" />
|
||||
<Compile Include="Configurations\UmbracoSettings\ContentElementTests.cs" />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Umbraco.Core.Request;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.AspNet
|
||||
{
|
||||
@@ -9,8 +11,13 @@ namespace Umbraco.Web.AspNet
|
||||
public AspNetRequestAccessor(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
|
||||
UmbracoModule.EndRequest += OnEndRequest;
|
||||
UmbracoModule.RouteAttempt += OnRouteAttempt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string GetRequestValue(string name)
|
||||
{
|
||||
return _httpContextAccessor.GetRequiredHttpContext().Request[name];
|
||||
@@ -20,5 +27,17 @@ namespace Umbraco.Web.AspNet
|
||||
{
|
||||
return _httpContextAccessor.GetRequiredHttpContext().Request.QueryString[name];
|
||||
}
|
||||
|
||||
private void OnEndRequest(object sender, UmbracoRequestEventArgs args)
|
||||
{
|
||||
EndRequest?.Invoke(sender, args);
|
||||
}
|
||||
|
||||
private void OnRouteAttempt(object sender, RoutableAttemptEventArgs args)
|
||||
{
|
||||
RouteAttempt?.Invoke(sender, args);
|
||||
}
|
||||
public event EventHandler<UmbracoRequestEventArgs> EndRequest;
|
||||
public event EventHandler<RoutableAttemptEventArgs> RouteAttempt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements <see cref="IAppPolicyCache"/> on top of a <see cref="System.Web.Caching.Cache"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The underlying cache is expected to be HttpRuntime.Cache.</remarks>
|
||||
internal class WebCachingAppCache : FastDictionaryAppCacheBase, IAppPolicyCache
|
||||
{
|
||||
// locker object that supports upgradeable read locking
|
||||
// does not need to support recursion if we implement the cache correctly and ensure
|
||||
// that methods cannot be reentrant, ie we do NOT create values while holding a lock.
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
|
||||
private readonly System.Web.Caching.Cache _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebCachingAppCache"/> class.
|
||||
/// </summary>
|
||||
public WebCachingAppCache(System.Web.Caching.Cache cache, ITypeFinder typeFinder) : base(typeFinder)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Get(string key, Func<object> factory)
|
||||
{
|
||||
return Get(key, factory, null, dependentFiles: null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Get(string key, Func<object> factory, TimeSpan? timeout, bool isSliding = false, string[] dependentFiles = null)
|
||||
{
|
||||
CacheDependency dependency = null;
|
||||
if (dependentFiles != null && dependentFiles.Any())
|
||||
{
|
||||
dependency = new CacheDependency(dependentFiles);
|
||||
}
|
||||
return GetImpl(key, factory, timeout, isSliding, dependency);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Insert(string key, Func<object> factory, TimeSpan? timeout = null, bool isSliding = false, string[] dependentFiles = null)
|
||||
{
|
||||
CacheDependency dependency = null;
|
||||
if (dependentFiles != null && dependentFiles.Any())
|
||||
{
|
||||
dependency = new CacheDependency(dependentFiles);
|
||||
}
|
||||
InsertImpl(key, factory, timeout, isSliding, dependency);
|
||||
}
|
||||
|
||||
#region Dictionary
|
||||
|
||||
protected override IEnumerable<DictionaryEntry> GetDictionaryEntries()
|
||||
{
|
||||
const string prefix = CacheItemPrefix + "-";
|
||||
return _cache.Cast<DictionaryEntry>()
|
||||
.Where(x => x.Key is string && ((string)x.Key).StartsWith(prefix));
|
||||
}
|
||||
|
||||
protected override void RemoveEntry(string key)
|
||||
{
|
||||
_cache.Remove(key);
|
||||
}
|
||||
|
||||
protected override object GetEntry(string key)
|
||||
{
|
||||
return _cache.Get(key);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lock
|
||||
|
||||
protected override void EnterReadLock()
|
||||
{
|
||||
_locker.EnterReadLock();
|
||||
}
|
||||
|
||||
protected override void EnterWriteLock()
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
}
|
||||
|
||||
protected override void ExitReadLock()
|
||||
{
|
||||
if (_locker.IsReadLockHeld)
|
||||
_locker.ExitReadLock();
|
||||
}
|
||||
|
||||
protected override void ExitWriteLock()
|
||||
{
|
||||
if (_locker.IsWriteLockHeld)
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private object GetImpl(string key, Func<object> factory, TimeSpan? timeout, bool isSliding = false, CacheDependency dependency = null)
|
||||
{
|
||||
key = GetCacheKey(key);
|
||||
|
||||
// NOTE - because we don't know what getCacheItem does, how long it will take and whether it will hang,
|
||||
// getCacheItem should run OUTSIDE of the global application lock else we run into lock contention and
|
||||
// nasty performance issues.
|
||||
|
||||
// So.... we insert a Lazy<object> in the cache while holding the global application lock, and then rely
|
||||
// on the Lazy lock to ensure that getCacheItem runs once and everybody waits on it, while the global
|
||||
// application lock has been released.
|
||||
|
||||
// NOTE
|
||||
// The Lazy value creation may produce a null value.
|
||||
// Must make sure (for backward compatibility) that we pretend they are not in the cache.
|
||||
// So if we find an entry in the cache that already has its value created and is null,
|
||||
// pretend it was not there. If value is not already created, wait... and return null, that's
|
||||
// what prior code did.
|
||||
|
||||
// NOTE
|
||||
// The Lazy value creation may throw.
|
||||
|
||||
// So... the null value _will_ be in the cache but never returned
|
||||
|
||||
Lazy<object> result;
|
||||
|
||||
// Fast!
|
||||
// Only one thread can enter an UpgradeableReadLock at a time, but it does not prevent other
|
||||
// threads to enter a ReadLock in the meantime -- only upgrading to WriteLock will prevent all
|
||||
// reads. We first try with a normal ReadLock for maximum concurrency and take the penalty of
|
||||
// having to re-lock in case there's no value. Would need to benchmark to figure out whether
|
||||
// it's worth it, though...
|
||||
try
|
||||
{
|
||||
_locker.EnterReadLock();
|
||||
result = _cache.Get(key) as Lazy<object>; // null if key not found
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_locker.IsReadLockHeld)
|
||||
_locker.ExitReadLock();
|
||||
}
|
||||
var value = result == null ? null : SafeLazy.GetSafeLazyValue(result);
|
||||
if (value != null) return value;
|
||||
|
||||
using (var lck = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
result = _cache.Get(key) as Lazy<object>; // null if key not found
|
||||
|
||||
// cannot create value within the lock, so if result.IsValueCreated is false, just
|
||||
// do nothing here - means that if creation throws, a race condition could cause
|
||||
// more than one thread to reach the return statement below and throw - accepted.
|
||||
|
||||
if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = SafeLazy.GetSafeLazy(factory);
|
||||
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
|
||||
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
|
||||
|
||||
lck.UpgradeToWriteLock();
|
||||
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
|
||||
_cache.Insert(key, result, dependency, absolute, sliding, CacheItemPriority.Normal, null);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
value = result.Value; // will not throw (safe lazy)
|
||||
if (value is SafeLazy.ExceptionHolder eh) eh.Exception.Throw(); // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
private void InsertImpl(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheDependency dependency = null)
|
||||
{
|
||||
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
|
||||
// and make sure we don't store a null value.
|
||||
|
||||
var result = SafeLazy.GetSafeLazy(getCacheItem);
|
||||
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
|
||||
if (value == null) return; // do not store null values (backward compat)
|
||||
|
||||
cacheKey = GetCacheKey(cacheKey);
|
||||
|
||||
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
|
||||
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
|
||||
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
|
||||
_cache.Insert(cacheKey, result, dependency, absolute, sliding, CacheItemPriority.Normal, null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_locker.IsWriteLockHeld)
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace Umbraco.Web
|
||||
}
|
||||
if (cacheByMember)
|
||||
{
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var helper = Current.MembershipHelper;
|
||||
var currentMember = helper.GetCurrentMember();
|
||||
cacheKey.AppendFormat("m{0}-", currentMember?.Id ?? 0);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Umbraco.Web.Macros
|
||||
private readonly IMemberUserKeyProvider _memberUserKeyProvider;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
|
||||
public MacroRenderer(
|
||||
@@ -45,7 +46,8 @@ namespace Umbraco.Web.Macros
|
||||
ICookieManager cookieManager,
|
||||
IMemberUserKeyProvider memberUserKeyProvider,
|
||||
ISessionManager sessionManager,
|
||||
IRequestAccessor requestAccessor)
|
||||
IRequestAccessor requestAccessor,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_plogger = plogger ?? throw new ArgumentNullException(nameof(plogger));
|
||||
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
|
||||
@@ -58,6 +60,7 @@ namespace Umbraco.Web.Macros
|
||||
_memberUserKeyProvider = memberUserKeyProvider;
|
||||
_sessionManager = sessionManager;
|
||||
_requestAccessor = requestAccessor;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
#region MacroContent cache
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.Security;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
@@ -16,26 +14,9 @@ namespace Umbraco.Web.Models
|
||||
/// <returns></returns>
|
||||
public static LoginStatusModel CreateModel()
|
||||
{
|
||||
return new LoginStatusModel(false);
|
||||
return new LoginStatusModel();
|
||||
}
|
||||
|
||||
private LoginStatusModel(bool doLookup)
|
||||
{
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var model = helper.GetCurrentLoginStatus();
|
||||
if (model != null)
|
||||
{
|
||||
Name = model.Name;
|
||||
Username = model.Username;
|
||||
Email = model.Email;
|
||||
IsLoggedIn = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of the member
|
||||
/// </summary>
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.ContentEditing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebApi;
|
||||
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
@@ -3,9 +3,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
@@ -28,7 +25,7 @@ namespace Umbraco.Web.Models
|
||||
MemberProperties = new List<UmbracoProperty>();
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var helper = Current.MembershipHelper;
|
||||
var model = helper.GetCurrentMemberProfileModel();
|
||||
MemberProperties = model.MemberProperties;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
@@ -20,22 +15,16 @@ namespace Umbraco.Web.Models
|
||||
/// <returns></returns>
|
||||
public static RegisterModel CreateModel()
|
||||
{
|
||||
return new RegisterModel(false);
|
||||
return new RegisterModel();
|
||||
}
|
||||
|
||||
private RegisterModel(bool doLookup)
|
||||
private RegisterModel()
|
||||
{
|
||||
MemberTypeAlias = Constants.Conventions.MemberTypes.DefaultAlias;
|
||||
UsernameIsEmail = true;
|
||||
MemberProperties = new List<UmbracoProperty>();
|
||||
LoginOnSuccess = true;
|
||||
CreatePersistentLoginCookie = true;
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var model = helper.CreateRegistrationModel(MemberTypeAlias);
|
||||
MemberProperties = model.MemberProperties;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ namespace Umbraco.Web.Mvc
|
||||
}
|
||||
}
|
||||
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var helper = Current.MembershipHelper;
|
||||
return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Web.Runtime
|
||||
composition.Register<ISessionIdResolver>(factory => factory.GetInstance<AspNetSessionManager>(), Lifetime.Singleton);
|
||||
composition.Register<ISessionManager>(factory => factory.GetInstance<AspNetSessionManager>(), Lifetime.Singleton);
|
||||
|
||||
composition.Register<IRequestAccessor, AspNetRequestAccessor>();
|
||||
composition.Register<IRequestAccessor, AspNetRequestAccessor>(Lifetime.Singleton);
|
||||
|
||||
composition.Register<IHostingEnvironment, AspNetHostingEnvironment>();
|
||||
composition.Register<IBackOfficeInfo, AspNetBackOfficeInfo>();
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace Umbraco.Web.Runtime
|
||||
/// <remarks>On top of CoreRuntime, handles all of the web-related runtime aspects of Umbraco.</remarks>
|
||||
public class WebRuntime : CoreRuntime
|
||||
{
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
private BuildManagerTypeFinder _typeFinder;
|
||||
|
||||
/// <summary>
|
||||
@@ -42,8 +41,6 @@ namespace Umbraco.Web.Runtime
|
||||
IMainDom mainDom):
|
||||
base(configs, umbracoVersion, ioHelper, logger, profiler ,new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom)
|
||||
{
|
||||
_umbracoApplication = umbracoApplication;
|
||||
|
||||
Profiler = GetWebProfiler();
|
||||
}
|
||||
|
||||
@@ -102,7 +99,7 @@ namespace Umbraco.Web.Runtime
|
||||
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 WebCachingAppCache(HttpRuntime.Cache, TypeFinder)),
|
||||
new DeepCloneAppCache(new ObjectCacheAppCache(TypeFinder)),
|
||||
// we need request based cache when running in web-based context
|
||||
new HttpRequestAppCache(() => HttpContext.Current?.Items, TypeFinder),
|
||||
new IsolatedCaches(type =>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Net.Mail;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using Microsoft.Owin.Security.Cookies;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
namespace Umbraco.Web.Security
|
||||
|
||||
@@ -2,16 +2,15 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Web.Templates
|
||||
{
|
||||
@@ -46,10 +45,11 @@ namespace Umbraco.Web.Templates
|
||||
{
|
||||
if (writer == null) throw new ArgumentNullException(nameof(writer));
|
||||
|
||||
var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
|
||||
// instantiate a request and process
|
||||
// important to use CleanedUmbracoUrl - lowercase path-only version of the current url, though this isn't going to matter
|
||||
// terribly much for this implementation since we are just creating a doc content request to modify it's properties manually.
|
||||
var contentRequest = _publishedRouter.CreateRequest(_umbracoContextAccessor.UmbracoContext);
|
||||
var contentRequest = _publishedRouter.CreateRequest(umbracoContext);
|
||||
|
||||
var doc = contentRequest.UmbracoContext.Content.GetById(pageId);
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Web.Templates
|
||||
//in some cases the UmbracoContext will not have a PublishedRequest assigned to it if we are not in the
|
||||
//execution of a front-end rendered page. In this case set the culture to the default.
|
||||
//set the culture to the same as is currently rendering
|
||||
if (_umbracoContextAccessor.UmbracoContext.PublishedRequest == null)
|
||||
if (umbracoContext.PublishedRequest == null)
|
||||
{
|
||||
var defaultLanguage = _languageService.GetAllLanguages().FirstOrDefault();
|
||||
contentRequest.Culture = defaultLanguage == null
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Web.Templates
|
||||
}
|
||||
else
|
||||
{
|
||||
contentRequest.Culture = _umbracoContextAccessor.UmbracoContext.PublishedRequest.Culture;
|
||||
contentRequest.Culture = umbracoContext.PublishedRequest.Culture;
|
||||
}
|
||||
|
||||
//set the doc that was found by id
|
||||
|
||||
@@ -139,7 +139,6 @@
|
||||
<Compile Include="AspNet\AspNetUserAgentProvider.cs" />
|
||||
<Compile Include="AspNet\FrameworkMarchal.cs" />
|
||||
<Compile Include="AspNet\AspNetUmbracoApplicationLifetime.cs" />
|
||||
<Compile Include="Cache\WebCachingAppCache.cs" />
|
||||
<Compile Include="Compose\AuditEventsComponent.cs" />
|
||||
<Compile Include="Compose\AuditEventsComposer.cs" />
|
||||
<Compile Include="Compose\BackOfficeUserAuditEventsComponent.cs" />
|
||||
@@ -192,8 +191,6 @@
|
||||
<Compile Include="Profiling\WebProfilingController.cs" />
|
||||
<Compile Include="RoutableDocumentFilter.cs" />
|
||||
<Compile Include="Runtime\AspNetUmbracoBootPermissionChecker.cs" />
|
||||
<Compile Include="Scheduling\SchedulerComponent.cs" />
|
||||
<Compile Include="Scheduling\SchedulerComposer.cs" />
|
||||
<Compile Include="Security\BackOfficeUserStore.cs" />
|
||||
<Compile Include="Security\BackOfficeUserValidator.cs" />
|
||||
<Compile Include="Security\ConfiguredPasswordValidator.cs" />
|
||||
@@ -307,7 +304,6 @@
|
||||
<Compile Include="Editors\Filters\MediaItemSaveValidationAttribute.cs" />
|
||||
<Compile Include="Editors\Filters\MemberSaveValidationAttribute.cs" />
|
||||
<Compile Include="WebApi\SessionHttpControllerRouteHandler.cs" />
|
||||
<Compile Include="WebApi\UmbracoApiControllerTypeCollection.cs" />
|
||||
<Compile Include="WebApi\UmbracoApiControllerTypeCollectionBuilder.cs" />
|
||||
<Compile Include="WebApi\UnhandedExceptionLoggerConfigurationAttribute.cs" />
|
||||
<Compile Include="WebApi\UnhandledExceptionLogger.cs" />
|
||||
@@ -344,7 +340,6 @@
|
||||
<Compile Include="IUmbracoComponentRenderer.cs" />
|
||||
<Compile Include="Mvc\ProfilingView.cs" />
|
||||
<Compile Include="Mvc\ProfilingViewEngine.cs" />
|
||||
<Compile Include="BatchedDatabaseServerMessenger.cs" />
|
||||
<Compile Include="CacheHelperExtensions.cs" />
|
||||
<Compile Include="Editors\AuthenticationController.cs" />
|
||||
<Compile Include="Controllers\UmbProfileController.cs" />
|
||||
@@ -527,7 +522,6 @@
|
||||
<Compile Include="Mvc\PluginControllerMetadata.cs" />
|
||||
<Compile Include="Mvc\UmbracoPageResult.cs" />
|
||||
<Compile Include="RouteCollectionExtensions.cs" />
|
||||
<Compile Include="Compose\DatabaseServerRegistrarAndMessengerComponent.cs" />
|
||||
<Compile Include="Templates\TemplateRenderer.cs" />
|
||||
<Compile Include="Trees\PartialViewMacrosTreeController.cs" />
|
||||
<Compile Include="Trees\PartialViewsTreeController.cs" />
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Umbraco.Web.WebApi
|
||||
}
|
||||
}
|
||||
|
||||
var helper = Current.Factory.GetInstance<MembershipHelper>();
|
||||
var helper = Current.MembershipHelper;
|
||||
return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user