From fde1b6685a98e175c03035883e5e5839963beb71 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Tue, 7 Jun 2022 10:35:36 +0100 Subject: [PATCH] Remove ambient scope stack from httpcontext.items. (#12539) This change makes it easier to use service calls in parallel whilst a httpcontext is available. --- .../UmbracoBuilder.CoreServices.cs | 7 +- .../Scoping/AmbientScopeContextStack.cs | 39 ++ .../Scoping/AmbientScopeStack.cs | 39 ++ .../Scoping/IAmbientScopeContextStack.cs | 10 + .../Scoping/IAmbientScopeStack.cs | 7 + src/Umbraco.Infrastructure/Scoping/Scope.cs | 23 +- .../Scoping/ScopeProvider.cs | 358 +++--------------- .../Scoping/ScopeTests.cs | 50 --- .../Services/ThreadSafetyServiceTest.cs | 10 - .../Umbraco.Core/Components/ComponentTests.cs | 2 +- .../ScopedNotificationPublisherTests.cs | 3 +- .../Scoping/ScopeUnitTests.cs | 3 +- 12 files changed, 164 insertions(+), 387 deletions(-) create mode 100644 src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs create mode 100644 src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs create mode 100644 src/Umbraco.Infrastructure/Scoping/IAmbientScopeContextStack.cs create mode 100644 src/Umbraco.Infrastructure/Scoping/IAmbientScopeStack.cs diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index 4b30a10159..48bdb6d399 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -95,11 +95,14 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection builder.Mappers()?.AddCoreMappers(); // register the scope provider - builder.Services.AddSingleton(); // implements IScopeProvider, IScopeAccessor + builder.Services.AddSingleton(sp => ActivatorUtilities.CreateInstance(sp, sp.GetRequiredService())); // implements IScopeProvider, IScopeAccessor builder.Services.AddSingleton(f => f.GetRequiredService()); builder.Services.AddSingleton(f => f.GetRequiredService()); builder.Services.AddSingleton(f => f.GetRequiredService()); - builder.Services.AddSingleton(f => f.GetRequiredService()); + + builder.Services.AddSingleton(); + builder.Services.AddSingleton(f => f.GetRequiredService()); + builder.Services.AddSingleton(); builder.Services.AddScoped(); diff --git a/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs b/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs new file mode 100644 index 0000000000..18e68120a6 --- /dev/null +++ b/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs @@ -0,0 +1,39 @@ +using System.Collections.Concurrent; +using Umbraco.Cms.Core.Scoping; + +namespace Umbraco.Cms.Infrastructure.Scoping; + +internal class AmbientScopeContextStack : IAmbientScopeContextStack +{ + private static AsyncLocal> _stack = new(); + + public IScopeContext? AmbientContext + { + get + { + if (_stack.Value?.TryPeek(out IScopeContext? ambientContext) ?? false) + { + return ambientContext; + } + + return null; + } + } + + public IScopeContext Pop() + { + if (_stack.Value?.TryPop(out IScopeContext? ambientContext) ?? false) + { + return ambientContext; + } + + throw new InvalidOperationException("No AmbientContext was found."); + } + + public void Push(IScopeContext scope) + { + _stack.Value ??= new ConcurrentStack(); + + _stack.Value.Push(scope); + } +} diff --git a/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs b/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs new file mode 100644 index 0000000000..3ad5e89e51 --- /dev/null +++ b/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs @@ -0,0 +1,39 @@ +using System.Collections.Concurrent; + +namespace Umbraco.Cms.Infrastructure.Scoping +{ + internal class AmbientScopeStack : IAmbientScopeStack + { + private static AsyncLocal> _stack = new (); + + public IScope? AmbientScope + { + get + { + if (_stack.Value?.TryPeek(out IScope? ambientScope) ?? false) + { + return ambientScope; + } + + return null; + } + } + + public IScope Pop() + { + if (_stack.Value?.TryPop(out IScope? ambientScope) ?? false) + { + return ambientScope; + } + + throw new InvalidOperationException("No AmbientScope was found."); + } + + public void Push(IScope scope) + { + _stack.Value ??= new ConcurrentStack(); + + _stack.Value.Push(scope); + } + } +} diff --git a/src/Umbraco.Infrastructure/Scoping/IAmbientScopeContextStack.cs b/src/Umbraco.Infrastructure/Scoping/IAmbientScopeContextStack.cs new file mode 100644 index 0000000000..28da9a6427 --- /dev/null +++ b/src/Umbraco.Infrastructure/Scoping/IAmbientScopeContextStack.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Core.Scoping; + +namespace Umbraco.Cms.Infrastructure.Scoping; + +internal interface IAmbientScopeContextStack +{ + IScopeContext? AmbientContext { get; } + IScopeContext Pop(); + void Push(IScopeContext scope); +} diff --git a/src/Umbraco.Infrastructure/Scoping/IAmbientScopeStack.cs b/src/Umbraco.Infrastructure/Scoping/IAmbientScopeStack.cs new file mode 100644 index 0000000000..71cfbf3a03 --- /dev/null +++ b/src/Umbraco.Infrastructure/Scoping/IAmbientScopeStack.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Cms.Infrastructure.Scoping; + +internal interface IAmbientScopeStack : IScopeAccessor +{ + IScope Pop(); + void Push(IScope scope); +} diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index e1ad1d2389..2fdc1a04dd 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -40,7 +40,6 @@ namespace Umbraco.Cms.Infrastructure.Scoping private readonly bool? _scopeFileSystem; private readonly ScopeProvider _scopeProvider; - private bool _callContext; private bool? _completed; private IUmbracoDatabase? _database; @@ -93,7 +92,6 @@ namespace Umbraco.Cms.Infrastructure.Scoping _eventDispatcher = eventDispatcher; _notificationPublisher = notificationPublisher; _scopeFileSystem = scopeFileSystems; - _callContext = callContext; _autoComplete = autoComplete; Detachable = detachable; _dictionaryLocker = new object(); @@ -259,24 +257,15 @@ namespace Umbraco.Cms.Infrastructure.Scoping { } + [Obsolete("Scopes are never stored on HttpContext.Items anymore, so CallContext is always true.")] // a value indicating whether to force call-context public bool CallContext { - get + get => true; + set { - if (_callContext) - { - return true; - } - - if (ParentScope != null) - { - return ParentScope.CallContext; - } - - return false; + // NOOP - always true. } - set => _callContext = value; } public bool ScopedFileSystems @@ -564,7 +553,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping } } - _scopeProvider.PopAmbientScope(this); // might be null = this is how scopes are removed from context objects + _scopeProvider.PopAmbientScope(); // might be null = this is how scopes are removed from context objects #if DEBUG_SCOPES _scopeProvider.Disposed(this); @@ -916,7 +905,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping // by Deploy which I don't fully understand since there is limited tests on this in the CMS if (OrigScope != _scopeProvider.AmbientScope) { - _scopeProvider.PopAmbientScope(_scopeProvider.AmbientScope); + _scopeProvider.PopAmbientScope(); } if (OrigContext != _scopeProvider.AmbientContext) diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 4022f366e2..9be7eee387 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -1,5 +1,5 @@ -using System; using System.Data; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Cache; @@ -8,10 +8,9 @@ using Umbraco.Cms.Core.IO; using Umbraco.Cms.Infrastructure.Persistence; using CoreDebugSettings = Umbraco.Cms.Core.Configuration.Models.CoreDebugSettings; using Umbraco.Extensions; -using System.Collections.Concurrent; -using System.Threading; using Umbraco.Cms.Core.DistributedLocking; using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Web.Common.DependencyInjection; #if DEBUG_SCOPES using System.Linq; @@ -27,20 +26,46 @@ namespace Umbraco.Cms.Infrastructure.Scoping ICoreScopeProvider, IScopeProvider, Core.Scoping.IScopeProvider, - IScopeAccessor + IScopeAccessor // TODO: No need to implement this here but literally hundreds of our tests cast ScopeProvider to ScopeAccessor { private readonly ILogger _logger; private readonly ILoggerFactory _loggerFactory; - private readonly IRequestCache _requestCache; + private readonly IEventAggregator _eventAggregator; + private readonly IAmbientScopeStack _ambientScopeStack; + private readonly IAmbientScopeContextStack _ambientContextStack; + private readonly FileSystems _fileSystems; private CoreDebugSettings _coreDebugSettings; private readonly MediaFileManager _mediaFileManager; - private static readonly AsyncLocal> s_scopeStack = new AsyncLocal>(); - private static readonly AsyncLocal> s_scopeContextStack = new AsyncLocal>(); - private static readonly string s_scopeItemKey = typeof(Scope).FullName!; - private static readonly string s_contextItemKey = typeof(ScopeProvider).FullName!; - private readonly IEventAggregator _eventAggregator; + public ScopeProvider( + IAmbientScopeStack ambientScopeStack, + IAmbientScopeContextStack ambientContextStack, + IDistributedLockingMechanismFactory distributedLockingMechanismFactory, + IUmbracoDatabaseFactory databaseFactory, + FileSystems fileSystems, + IOptionsMonitor coreDebugSettings, + MediaFileManager mediaFileManager, + ILoggerFactory loggerFactory, + IEventAggregator eventAggregator) + { + DistributedLockingMechanismFactory = distributedLockingMechanismFactory; + DatabaseFactory = databaseFactory; + _ambientScopeStack = ambientScopeStack; + _ambientContextStack = ambientContextStack; + _fileSystems = fileSystems; + _coreDebugSettings = coreDebugSettings.CurrentValue; + _mediaFileManager = mediaFileManager; + _logger = loggerFactory.CreateLogger(); + _loggerFactory = loggerFactory; + _eventAggregator = eventAggregator; + // take control of the FileSystems + _fileSystems.IsScoped = () => AmbientScope != null && AmbientScope.ScopedFileSystems; + + coreDebugSettings.OnChange(x => _coreDebugSettings = x); + } + + [Obsolete("Please use an alternative constructor. This constructor is due for removal in v12.")] public ScopeProvider( IDistributedLockingMechanismFactory distributedLockingMechanismFactory, IUmbracoDatabaseFactory databaseFactory, @@ -50,20 +75,17 @@ namespace Umbraco.Cms.Infrastructure.Scoping ILoggerFactory loggerFactory, IRequestCache requestCache, IEventAggregator eventAggregator) + : this( + StaticServiceProvider.Instance.GetRequiredService(), + StaticServiceProvider.Instance.GetRequiredService(), + distributedLockingMechanismFactory, + databaseFactory, + fileSystems, + coreDebugSettings, + mediaFileManager, + loggerFactory, + eventAggregator) { - DistributedLockingMechanismFactory = distributedLockingMechanismFactory; - DatabaseFactory = databaseFactory; - _fileSystems = fileSystems; - _coreDebugSettings = coreDebugSettings.CurrentValue; - _mediaFileManager = mediaFileManager; - _logger = loggerFactory.CreateLogger(); - _loggerFactory = loggerFactory; - _requestCache = requestCache; - _eventAggregator = eventAggregator; - // take control of the FileSystems - _fileSystems.IsScoped = () => AmbientScope != null && AmbientScope.ScopedFileSystems; - - coreDebugSettings.OnChange(x => _coreDebugSettings = x); } public IDistributedLockingMechanismFactory DistributedLockingMechanismFactory { get; } @@ -72,195 +94,6 @@ namespace Umbraco.Cms.Infrastructure.Scoping public ISqlContext SqlContext => DatabaseFactory.SqlContext; - #region Context - - private void MoveHttpContextScopeToCallContext() - { - var source = (ConcurrentStack?)_requestCache.Get(s_scopeItemKey); - ConcurrentStack? stack = s_scopeStack.Value; - MoveContexts(s_scopeItemKey, source, stack, (_, v) => s_scopeStack.Value = v); - } - - private void MoveHttpContextScopeContextToCallContext() - { - var source = (ConcurrentStack?)_requestCache.Get(s_contextItemKey); - ConcurrentStack? stack = s_scopeContextStack.Value; - MoveContexts(s_contextItemKey, source, stack, (_, v) => s_scopeContextStack.Value = v); - } - - private void MoveCallContextScopeToHttpContext() - { - ConcurrentStack? source = s_scopeStack.Value; - var stack = (ConcurrentStack?)_requestCache.Get(s_scopeItemKey); - MoveContexts(s_scopeItemKey, source, stack, (k, v) => _requestCache.Set(k, v)); - } - - private void MoveCallContextScopeContextToHttpContext() - { - ConcurrentStack? source = s_scopeContextStack.Value; - var stack = (ConcurrentStack?)_requestCache.Get(s_contextItemKey); - MoveContexts(s_contextItemKey, source, stack, (k, v) => _requestCache.Set(k, v)); - } - - private void MoveContexts(string key, ConcurrentStack? source, ConcurrentStack? stack, Action> setter) - where T : class, IInstanceIdentifiable - { - if (source == null) - { - return; - } - - if (stack != null) - { - stack.Clear(); - } - else - { - // TODO: This isn't going to copy it back up the execution context chain - stack = new ConcurrentStack(); - setter(key, stack); - } - - var arr = new T[source.Count]; - source.CopyTo(arr, 0); - Array.Reverse(arr); - foreach (T a in arr) - { - stack.Push(a); - } - - source.Clear(); - } - - private void SetCallContextScope(IScope? value) - { - ConcurrentStack? stack = s_scopeStack.Value; - -#if DEBUG_SCOPES - // first, null-register the existing value - if (stack != null && stack.TryPeek(out IScope ambientScope)) - { - RegisterContext(ambientScope, null); - } - - // then register the new value - if (value != null) - { - RegisterContext(value, "call"); - } -#endif - - if (value == null) - { - if (stack != null) - { - stack.TryPop(out _); - } - } - else - { - -#if DEBUG_SCOPES - _logger.LogDebug("AddObject " + value.InstanceId.ToString("N").Substring(0, 8)); -#endif - if (stack == null) - { - stack = new ConcurrentStack(); - } - stack.Push(value); - s_scopeStack.Value = stack; - } - } - - private void SetCallContextScopeContext(IScopeContext? value) - { - ConcurrentStack? stack = s_scopeContextStack.Value; - - if (value == null) - { - if (stack != null) - { - stack.TryPop(out _); - } - } - else - { - if (stack == null) - { - stack = new ConcurrentStack(); - } - stack.Push(value); - s_scopeContextStack.Value = stack; - } - } - - - private T? GetHttpContextObject(string key, bool required = true) - where T : class - { - if (!_requestCache.IsAvailable && required) - { - throw new Exception("Request cache is unavailable."); - } - - var stack = (ConcurrentStack?)_requestCache.Get(key); - return stack != null && stack.TryPeek(out T? peek) ? peek : null; - } - - private bool SetHttpContextObject(string key, T? value, bool required = true) - { - if (!_requestCache.IsAvailable) - { - if (required) - { - throw new Exception("Request cache is unavailable."); - } - - return false; - } - -#if DEBUG_SCOPES - // manage the 'context' that contains the scope (null, "http" or "call") - // only for scopes of course! - if (key == s_scopeItemKey) - { - // first, null-register the existing value - var ambientScope = (IScope)_requestCache.Get(s_scopeItemKey); - if (ambientScope != null) - { - RegisterContext(ambientScope, null); - } - - // then register the new value - if (value is IScope scope) - { - RegisterContext(scope, "http"); - } - } -#endif - var stack = (ConcurrentStack?)_requestCache.Get(key); - - if (value == null) - { - if (stack != null) - { - stack.TryPop(out _); - } - } - else - { - if (stack == null) - { - stack = new ConcurrentStack(); - } - stack.Push(value); - _requestCache.Set(key, stack); - } - - return true; - } - - #endregion #region Ambient Context @@ -270,83 +103,23 @@ namespace Umbraco.Cms.Infrastructure.Scoping /// /// The current execution context may be request based (HttpContext) or on a background thread (AsyncLocal) /// - public IScopeContext? AmbientContext - { - get - { - // try http context, fallback onto call context - IScopeContext? value = GetHttpContextObject(s_contextItemKey, false); - if (value != null) - { - return value; - } - - ConcurrentStack? stack = s_scopeContextStack.Value; - if (stack == null || !stack.TryPeek(out IScopeContext? peek)) - { - return null; - } - - return peek; - } - } + public IScopeContext? AmbientContext => _ambientContextStack.AmbientContext; #endregion #region Ambient Scope - IScope? IScopeAccessor.AmbientScope => AmbientScope; - /// /// Gets or set the Ambient (Current) for the current execution context. /// /// /// The current execution context may be request based (HttpContext) or on a background thread (AsyncLocal) /// - public Scope? AmbientScope - { - get - { - // try http context, fallback onto call context - IScope? value = GetHttpContextObject(s_scopeItemKey, false); - if (value != null) - { - return (Scope)value; - } + public Scope? AmbientScope => (Scope?)_ambientScopeStack.AmbientScope; - ConcurrentStack? stack = s_scopeStack.Value; - if (stack == null || !stack.TryPeek(out IScope? peek)) - { - return null; - } + IScope? IScopeAccessor.AmbientScope => _ambientScopeStack.AmbientScope; - return (Scope)peek; - } - } - - public void PopAmbientScope(Scope? scope) - { - // pop the stack from all contexts - SetHttpContextObject(s_scopeItemKey, null, false); - SetCallContextScope(null); - - // We need to move the stack to a different context if the parent scope - // is flagged with a different CallContext flag. This is required - // if creating a child scope with callContext: true (thus forcing CallContext) - // when there is actually a current HttpContext available. - // It's weird but is required for Deploy somehow. - bool parentScopeCallContext = (scope?.ParentScope?.CallContext ?? false); - if ((scope?.CallContext ?? false) && !parentScopeCallContext) - { - MoveCallContextScopeToHttpContext(); - MoveCallContextScopeContextToHttpContext(); - } - else if ((!scope?.CallContext ?? false) && parentScopeCallContext) - { - MoveHttpContextScopeToCallContext(); - MoveHttpContextScopeContextToCallContext(); - } - } + public void PopAmbientScope() => _ambientScopeStack.Pop(); #endregion @@ -357,22 +130,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping throw new ArgumentNullException(nameof(scope)); } - if (scope.CallContext != false || !SetHttpContextObject(s_scopeItemKey, scope, false)) - { - // In this case, always ensure that the HttpContext items - // is transfered to CallContext and then cleared since we - // may be migrating context with the callContext = true flag. - // This is a weird case when forcing callContext when HttpContext - // is available. Required by Deploy. - - if (_requestCache.IsAvailable) - { - MoveHttpContextScopeToCallContext(); - MoveHttpContextScopeContextToCallContext(); - } - - SetCallContextScope(scope); - } + _ambientScopeStack.Push(scope); } public void PushAmbientScopeContext(IScopeContext? scopeContext) @@ -381,17 +139,10 @@ namespace Umbraco.Cms.Infrastructure.Scoping { throw new ArgumentNullException(nameof(scopeContext)); } - - SetHttpContextObject(s_contextItemKey, scopeContext, false); - SetCallContextScopeContext(scopeContext); + _ambientContextStack.Push(scopeContext); } - public void PopAmbientScopeContext() - { - // pop stack from all contexts - SetHttpContextObject(s_contextItemKey, null, false); - SetCallContextScopeContext(null); - } + public void PopAmbientScopeContext() => _ambientContextStack.Pop(); /// public IScope CreateDetachedScope( @@ -445,7 +196,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping throw new InvalidOperationException("Ambient scope is not detachable."); } - PopAmbientScope(ambientScope); + PopAmbientScope(); PopAmbientScopeContext(); Scope? originalScope = AmbientScope; @@ -499,9 +250,6 @@ namespace Umbraco.Cms.Infrastructure.Scoping /// public IScopeContext? Context => AmbientContext; - // for testing - internal ConcurrentStack? GetCallContextScopeValue() => s_scopeStack.Value; - #if DEBUG_SCOPES // this code needs TLC // diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeTests.cs index cfd9e49583..5febb2819b 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Scoping/ScopeTests.cs @@ -226,56 +226,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping Assert.IsNull(scopeProvider.AmbientScope); } - [Test] - public void NestedMigrateScope() - { - // Get the request cache mock and re-configure it to be available and used - var requestCacheDictionary = new Dictionary(); - IRequestCache requestCache = AppCaches.RequestCache; - var requestCacheMock = Mock.Get(requestCache); - requestCacheMock - .Setup(x => x.IsAvailable) - .Returns(true); - requestCacheMock - .Setup(x => x.Set(It.IsAny(), It.IsAny())) - .Returns((string key, object val) => - { - requestCacheDictionary.Add(key, val); - return true; - }); - requestCacheMock - .Setup(x => x.Get(It.IsAny())) - .Returns((string key) => requestCacheDictionary.TryGetValue(key, out var val) ? val : null); - - ScopeProvider scopeProvider = ScopeProvider; - Assert.IsNull(scopeProvider.AmbientScope); - - using (IScope scope = scopeProvider.CreateScope()) - { - Assert.IsInstanceOf(scope); - Assert.IsNotNull(scopeProvider.AmbientScope); - Assert.AreSame(scope, scopeProvider.AmbientScope); - - using (IScope nested = scopeProvider.CreateScope(callContext: true)) - { - Assert.IsInstanceOf(nested); - Assert.IsNotNull(scopeProvider.AmbientScope); - Assert.AreSame(nested, scopeProvider.AmbientScope); - Assert.AreSame(scope, ((Scope)nested).ParentScope); - - // it's moved over to call context - ConcurrentStack callContextScope = scopeProvider.GetCallContextScopeValue(); - - Assert.IsNotNull(callContextScope); - Assert.AreEqual(2, callContextScope.Count); - } - - // it's naturally back in http context - } - - Assert.IsNull(scopeProvider.AmbientScope); - } - [Test] public void NestedCreateScopeContext() { diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs index 88adef3824..4ee52a6869 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs @@ -134,11 +134,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services { try { - ConcurrentStack - currentStack = ((ScopeProvider)ScopeProvider).GetCallContextScopeValue(); - log.LogInformation("[{ThreadId}] Current Stack? {CurrentStack}", - Thread.CurrentThread.ManagedThreadId, currentStack?.Count); - // NOTE: This is NULL because we have supressed the execution context flow. // If we don't do that we will get various exceptions because we're trying to run concurrent threads // against an ambient context which cannot be done due to the rules of scope creation and completion. @@ -234,11 +229,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services { try { - ConcurrentStack - currentStack = ((ScopeProvider)ScopeProvider).GetCallContextScopeValue(); - log.LogInformation("[{ThreadId}] Current Stack? {CurrentStack}", - Thread.CurrentThread.ManagedThreadId, currentStack?.Count); - // NOTE: This is NULL because we have supressed the execution context flow. // If we don't do that we will get various exceptions because we're trying to run concurrent threads // against an ambient context which cannot be done due to the rules of scope creation and completion. diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index 7593e52511..8aca86ba80 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Components Mock.Of(), Options.Create(new ContentSettings())); IEventAggregator eventAggregator = Mock.Of(); - var scopeProvider = new ScopeProvider(Mock.Of(),f , fs, new TestOptionsMonitor(coreDebug), mediaFileManager, loggerFactory, NoAppCache.Instance, eventAggregator); + var scopeProvider = new ScopeProvider(new AmbientScopeStack(), new AmbientScopeContextStack(), Mock.Of(),f , fs, new TestOptionsMonitor(coreDebug), mediaFileManager, loggerFactory, eventAggregator); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(logger); mock.Setup(x => x.GetService(typeof(ILogger))).Returns(loggerFactory.CreateLogger); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopedNotificationPublisherTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopedNotificationPublisherTests.cs index 6ddc506753..79d2f7b3d3 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopedNotificationPublisherTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/ScopedNotificationPublisherTests.cs @@ -93,13 +93,14 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Scoping eventAggregatorMock = new Mock(); return new ScopeProvider( + new AmbientScopeStack(), + new AmbientScopeContextStack(), Mock.Of(), Mock.Of(), fileSystems, new TestOptionsMonitor(new CoreDebugSettings()), mediaFileManager, loggerFactory, - Mock.Of(), eventAggregatorMock.Object ); } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs index 5734622e3e..3d4ded44f2 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Scoping/ScopeUnitTests.cs @@ -71,13 +71,14 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Scoping sqlContext.Setup(x => x.SqlSyntax).Returns(syntaxProviderMock.Object); return new ScopeProvider( + new AmbientScopeStack(), + new AmbientScopeContextStack(), lockingMechanismFactory.Object, databaseFactory.Object, fileSystems, new TestOptionsMonitor(new CoreDebugSettings()), mediaFileManager, loggerFactory, - Mock.Of(), Mock.Of()); }