diff --git a/DNN Platform/Library/Common/Extensions/HttpContextDependencyInjectionExtensions.cs b/DNN Platform/Library/Common/Extensions/HttpContextDependencyInjectionExtensions.cs
index a7806b7e3f2..645cfc7ad3e 100644
--- a/DNN Platform/Library/Common/Extensions/HttpContextDependencyInjectionExtensions.cs
+++ b/DNN Platform/Library/Common/Extensions/HttpContextDependencyInjectionExtensions.cs
@@ -11,56 +11,86 @@ namespace DotNetNuke.Common.Extensions
/// Dependency injection extensions for HttpContext.
public static class HttpContextDependencyInjectionExtensions
{
- /// Sets the service scope for the http context base.
- /// The http context base.
- /// The service scope.
- public static void SetScope(this HttpContextBase httpContext, IServiceScope scope)
- {
- httpContext.Items[typeof(IServiceScope)] = scope;
- }
-
/// Sets the service scope for the http context.
/// The http context.
/// The service scope.
public static void SetScope(this HttpContext httpContext, IServiceScope scope)
+ => SetScope(new HttpContextWrapper(httpContext), scope);
+
+ /// Sets the service scope for the http context base.
+ /// The http context base.
+ /// The service scope.
+ public static void SetScope(this HttpContextBase httpContext, IServiceScope scope)
{
- httpContext.Items[typeof(IServiceScope)] = scope;
+ if (!httpContext.Items.Contains(typeof(IServiceScope)))
+ {
+ httpContext.Items[typeof(IServiceScope)] = scope;
+ }
}
/// Clears the service scope for the http context.
/// The http context on which to clear the service scope.
public static void ClearScope(this HttpContext httpContext)
+ => ClearScope(new HttpContextWrapper(httpContext));
+
+ /// Clears the service scope for the http context.
+ /// The http context on which to clear the service scope.
+ public static void ClearScope(this HttpContextBase httpContext)
{
httpContext.Items.Remove(typeof(IServiceScope));
}
+ /// Gets the http context service scope.
+ /// The http context from which to get the scope from.
+ /// A service scope.
+ public static IServiceScope GetScope(this HttpContext httpContext)
+ => GetScope(new HttpContextWrapper(httpContext));
+
/// Gets the http context base service scope.
/// The http context base from which to get the scope from.
/// A service scope.
public static IServiceScope GetScope(this HttpContextBase httpContext)
{
- return GetScope(httpContext.Items);
- }
+ if (httpContext.Items.Contains(typeof(IServiceScope)))
+ {
+ return httpContext.Items[typeof(IServiceScope)] as IServiceScope;
+ }
- /// Gets the http context service scope.
- /// The http context from which to get the scope from.
- /// A service scope.
- public static IServiceScope GetScope(this HttpContext httpContext)
- {
- return GetScope(httpContext.Items);
- }
+ var scopeLock = new object();
+ const string ScopeLockName = "GetScope_lock";
+ if (httpContext.Items.Contains(ScopeLockName))
+ {
+ // another thread is adding the scope, try again
+ return GetScope(httpContext);
+ }
- /// Gets the service scope from a collection of context items.
- /// A dictionary of context items.
- /// The found service scope.
- internal static IServiceScope GetScope(System.Collections.IDictionary contextItems)
- {
- if (!contextItems.Contains(typeof(IServiceScope)))
+ IServiceScope scope = null;
+ httpContext.Items.Add(ScopeLockName, scopeLock);
+ lock (httpContext.Items[ScopeLockName])
+ {
+ if (httpContext.Items[ScopeLockName] == scopeLock)
+ {
+ if (!httpContext.Items.Contains(typeof(IServiceScope)))
+ {
+ scope = Globals.DependencyProvider.CreateScope();
+ httpContext.Items[typeof(IServiceScope)] = scope;
+ }
+ }
+ }
+
+ if (scope is not null)
{
- return null;
+ httpContext.AddOnRequestCompleted(DisposeScope);
+ return scope;
}
- return contextItems[typeof(IServiceScope)] is IServiceScope scope ? scope : null;
+ return GetScope(httpContext);
+ }
+
+ private static void DisposeScope(HttpContextBase httpContext)
+ {
+ httpContext.GetScope()?.Dispose();
+ httpContext.ClearScope();
}
}
}
diff --git a/DNN Platform/Library/DotNetNuke.Library.csproj b/DNN Platform/Library/DotNetNuke.Library.csproj
index 20c776ff562..00a3d76f362 100644
--- a/DNN Platform/Library/DotNetNuke.Library.csproj
+++ b/DNN Platform/Library/DotNetNuke.Library.csproj
@@ -751,6 +751,7 @@
+
diff --git a/DNN Platform/Library/Services/DependencyInjection/IScopeAccessor.cs b/DNN Platform/Library/Services/DependencyInjection/IScopeAccessor.cs
index 92f02d18291..42f704084a0 100644
--- a/DNN Platform/Library/Services/DependencyInjection/IScopeAccessor.cs
+++ b/DNN Platform/Library/Services/DependencyInjection/IScopeAccessor.cs
@@ -4,39 +4,13 @@
namespace DotNetNuke.Services.DependencyInjection
{
- using System;
- using System.Collections;
- using System.Web;
-
- using DotNetNuke.Common.Extensions;
using Microsoft.Extensions.DependencyInjection;
+ /// A contract specifying the ability to access an instance.
public interface IScopeAccessor
- {
+ {
+ /// Gets the scope.
+ /// The scope, or if there is no scope to get.
IServiceScope GetScope();
}
-
- public class ScopeAccessor : IScopeAccessor
- {
- private static Func fallbackGetContextItems = () => HttpContext.Current?.Items;
-
- private Func getContextItems;
-
- /// Initializes a new instance of the class.
- public ScopeAccessor()
- {
- this.getContextItems = fallbackGetContextItems;
- }
-
- ///
- public IServiceScope GetScope()
- {
- return HttpContextDependencyInjectionExtensions.GetScope(this.getContextItems());
- }
-
- internal void SetContextItemsFunc(Func getContextItems)
- {
- this.getContextItems = getContextItems ?? fallbackGetContextItems;
- }
- }
}
diff --git a/DNN Platform/Library/Services/DependencyInjection/ScopeAccessor.cs b/DNN Platform/Library/Services/DependencyInjection/ScopeAccessor.cs
new file mode 100644
index 00000000000..272d548f465
--- /dev/null
+++ b/DNN Platform/Library/Services/DependencyInjection/ScopeAccessor.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
+
+namespace DotNetNuke.Services.DependencyInjection;
+
+using DotNetNuke.Common;
+using DotNetNuke.Common.Extensions;
+using Microsoft.Extensions.DependencyInjection;
+
+/// An implementation using .
+public class ScopeAccessor : IScopeAccessor
+{
+ ///
+ public IServiceScope GetScope()
+ {
+ return HttpContextSource.Current.GetScope();
+ }
+}