Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to create a ServiceScope without a HttpContext #540

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 21 additions & 23 deletions Composite/Core/ServiceLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using Composite.Core.Configuration;
using Composite.Core.Threading;
using Microsoft.Extensions.DependencyInjection;

namespace Composite.Core
Expand All @@ -19,7 +19,7 @@ namespace Composite.Core
/// </remarks>
public static class ServiceLocator
{
private const string HttpContextKey = "HttpApplication.ServiceScope";
private const string ThreadDataManagerKey = "ServiceScope";
private static IServiceCollection _serviceCollection = new ServiceCollection();
private static IServiceProvider _serviceProvider;
private static ConcurrentDictionary<Type, bool> _hasTypeLookup = new ConcurrentDictionary<Type, bool>();
Expand Down Expand Up @@ -120,7 +120,7 @@ public static IServiceProvider ServiceProvider
{
Verify.IsNotNull(_serviceProvider,"IServiceProvider not build - call out of expected sequence.");

return RequestScopedServiceProvider ?? _serviceProvider;
return ScopedServiceProvider ?? _serviceProvider;
}
}

Expand Down Expand Up @@ -188,48 +188,46 @@ internal static void BuildServiceProvider()


/// <summary>
/// Creates a service scope associated with the current http context
/// Creates a service scope associated with the current thread
/// </summary>
internal static void CreateRequestServicesScope(HttpContext context)
public static void CreateServiceScope()
{
Verify.ArgumentNotNull(context, nameof(context));
var threadDataManager = ThreadDataManager.GetCurrentNotNull();

Verify.IsFalse(threadDataManager.HasValue(ThreadDataManagerKey), "Multiple calls to CreateServicesScope unexpected");
Verify.IsNotNull(_serviceProvider, "ServiceProvider not initialized yet");
Verify.IsNull(context.Items[HttpContextKey], "Multiple calls to CreateRequestServicesScope unexpected");

var serviceScopeFactory = (IServiceScopeFactory)_serviceProvider.GetService(typeof(IServiceScopeFactory));
var serviceScope = serviceScopeFactory.CreateScope();

context.Items[HttpContextKey] = serviceScope;
threadDataManager.SetValue(ThreadDataManagerKey, serviceScope);
}


/// <summary>
/// Disposes a service scope associated with the current http context
/// Disposes a service scope associated with the current thread
/// </summary>
internal static void DisposeRequestServicesScope(HttpContext context)
public static void DisposeServiceScope()
{
Verify.ArgumentNotNull(context, nameof(context));
var scope = (IServiceScope)context.Items[HttpContextKey];
if (scope != null)
{
scope.Dispose();
}
var threadDataManager = ThreadDataManager.GetCurrentNotNull();
var scope = (IServiceScope)threadDataManager.GetValue(ThreadDataManagerKey);

scope?.Dispose();
threadDataManager.SetValue(ThreadDataManagerKey, null);
}


/// <summary>
/// Return a IServiceScope - if a scope has been initialized on the request (HttpContext) a scoped provider is returned.
/// Return a IServiceScope - if a scope has been initialized on the thread a scoped provider is returned.
/// </summary>
private static IServiceProvider RequestScopedServiceProvider
private static IServiceProvider ScopedServiceProvider
{
get
{
var context = HttpContext.Current;
if (context == null) return null;

var scope = (IServiceScope)context.Items[HttpContextKey];
var threadDataManager = ThreadDataManager.Current;
var scope = (IServiceScope) threadDataManager?.GetValue(ThreadDataManagerKey);

return scope != null ? scope.ServiceProvider : null;
return scope?.ServiceProvider;
}
}

Expand Down
6 changes: 3 additions & 3 deletions Composite/Core/WebClient/ApplicationLevelEventHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public static void Application_BeginRequest(object sender, EventArgs e)

if (SystemSetupFacade.IsSystemFirstTimeInitialized)
{
ServiceLocator.CreateRequestServicesScope(context);
ServiceLocator.CreateServiceScope();
}

if (LogRequestDetails)
Expand All @@ -193,7 +193,7 @@ public static void Application_EndRequest(object sender, EventArgs e)

try
{
ServiceLocator.DisposeRequestServicesScope(context);
ServiceLocator.DisposeServiceScope();

if (LogRequestDetails && context.Items.Contains("Global.asax timer"))
{
Expand Down Expand Up @@ -353,7 +353,7 @@ public static void ApplicationStartInitialize(bool displayDebugInfo = false)
ApplicationStartupFacade.FireConfigureServices(ServiceLocator.ServiceCollection);

ServiceLocator.BuildServiceProvider();
ServiceLocator.CreateRequestServicesScope(HttpContext.Current);
ServiceLocator.CreateServiceScope();

ApplicationStartupFacade.FireBeforeSystemInitialize(ServiceLocator.ServiceProvider);
}
Expand Down