From 6a79f5f8a79a4c6a0a2e33ce42df018ef3aec77f Mon Sep 17 00:00:00 2001 From: Cao Trong Thang Date: Mon, 28 Jun 2021 18:37:19 +0700 Subject: [PATCH] Support PerRequestLifetimeManager --- src/App_Start/UnityWebApiActivator.cs.pp | 3 + src/PerRequestLifetimeManager.cs | 53 +++++++++++++++ src/UnityPerRequestHttpModule.cs | 87 ++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/PerRequestLifetimeManager.cs create mode 100644 src/UnityPerRequestHttpModule.cs diff --git a/src/App_Start/UnityWebApiActivator.cs.pp b/src/App_Start/UnityWebApiActivator.cs.pp index 31d7e2a..2d25fd6 100644 --- a/src/App_Start/UnityWebApiActivator.cs.pp +++ b/src/App_Start/UnityWebApiActivator.cs.pp @@ -23,6 +23,9 @@ var resolver = new UnityDependencyResolver(UnityConfig.Container); GlobalConfiguration.Configuration.DependencyResolver = resolver; + + // Uncomment if you want to use PerRequestLifetimeManager + // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule)); } /// diff --git a/src/PerRequestLifetimeManager.cs b/src/PerRequestLifetimeManager.cs new file mode 100644 index 0000000..a3bc043 --- /dev/null +++ b/src/PerRequestLifetimeManager.cs @@ -0,0 +1,53 @@ +using System; +using Unity.Lifetime; + +namespace Unity.AspNet.WebApi +{ + public class PerRequestLifetimeManager : LifetimeManager, + IInstanceLifetimeManager, + IFactoryLifetimeManager, + ITypeLifetimeManager + { + private readonly object _lifetimeKey = new object(); + + /// + /// Retrieves a value from the backing store associated with this lifetime policy. + /// + /// The desired object, or null if no such object is currently stored. + public override object GetValue(ILifetimeContainer container = null) + { + return UnityPerRequestHttpModule.GetValue(_lifetimeKey); + } + + /// + /// Stores the given value into the backing store for retrieval later. + /// + /// The object being stored. + /// + public override void SetValue(object newValue, ILifetimeContainer container = null) + { + UnityPerRequestHttpModule.SetValue(_lifetimeKey, newValue); + } + + /// + /// Removes the given object from the backing store. + /// + public override void RemoveValue(ILifetimeContainer container = null) + { + var disposable = GetValue() as IDisposable; + + disposable?.Dispose(); + + UnityPerRequestHttpModule.SetValue(_lifetimeKey, null); + } + + /// + /// Creates clone + /// + /// + protected override LifetimeManager OnCreateLifetimeManager() + { + return new PerRequestLifetimeManager(); + } + } +} diff --git a/src/UnityPerRequestHttpModule.cs b/src/UnityPerRequestHttpModule.cs new file mode 100644 index 0000000..0f49cbd --- /dev/null +++ b/src/UnityPerRequestHttpModule.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Unity.Lifetime; + +namespace Unity.AspNet.WebApi +{ + public class UnityPerRequestHttpModule : IHttpModule + { + private static readonly object ModuleKey = new object(); + + internal static object GetValue(object lifetimeManagerKey) + { + var dict = GetDictionary(HttpContext.Current); + + if (dict != null) + { + if (dict.TryGetValue(lifetimeManagerKey, out var obj)) + { + return obj; + } + } + + return LifetimeManager.NoValue; + } + + internal static void SetValue(object lifetimeManagerKey, object value) + { + var dict = GetDictionary(HttpContext.Current); + + if (dict == null) + { + dict = new Dictionary(); + + HttpContext.Current.Items[ModuleKey] = dict; + } + + dict[lifetimeManagerKey] = value; + } + + /// + /// Disposes the resources used by this module. + /// + public void Dispose() + { + } + + /// + /// Initializes a module and prepares it to handle requests. + /// + /// An that provides access to the methods, properties, + /// and events common to all application objects within an ASP.NET application. + public void Init(HttpApplication context) + { + (context ?? throw new ArgumentNullException(nameof(context))).EndRequest += OnEndRequest; + } + + private void OnEndRequest(object sender, EventArgs e) + { + var app = (HttpApplication)sender; + + var dict = GetDictionary(app.Context); + + if (dict != null) + { + foreach (var disposable in dict.Values.OfType()) + { + disposable.Dispose(); + } + } + } + + private static Dictionary GetDictionary(HttpContext context) + { + if (context == null) + { + throw new InvalidOperationException( + "The PerRequestLifetimeManager can only be used in the context of an HTTP request.Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context."); + } + + var dict = (Dictionary)context.Items[ModuleKey]; + + return dict; + } + } +}