From 616f8a538b4011da844e1003e83f5771546405cc Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Thu, 28 Jan 2016 15:25:06 -0500 Subject: [PATCH] Fixed PerRequest dependency resolution in pipeline processor context --- .../Jabberwocky.Glass.Autofac.Mvc.csproj | 6 ++ .../Providers/MvcLifetimeScopeProvider.cs | 14 +++ .../Processors/GetModelFromViewProcessor.cs | 2 +- .../Pipelines/Processors/GetModelProcessor.cs | 2 +- Jabberwocky.Glass.Autofac.Mvc/packages.config | 1 + .../Jabberwocky.Glass.Autofac.WebApi.csproj | 87 +++++++++++++++++++ .../Providers/WebApiLifetimeScopeProvider.cs | 19 ++++ .../Properties/AssemblyInfo.cs | 36 ++++++++ .../packages.config | 9 ++ .../SitecorePipelineRegistrationExtensions.cs | 13 ++- .../Jabberwocky.Glass.Autofac.csproj | 3 + .../Factories/AutofacProcessorFactory.cs | 18 +++- .../Factories/DefaultLifetimeScopeFactory.cs | 26 ++++++ .../Factories/ILifetimeScopeFactory.cs | 9 ++ .../Providers/ILifetimeScopeProvider.cs | 9 ++ .../Properties/AssemblyInfo.cs | 3 + Jabberwocky.sln | 9 +- 17 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 Jabberwocky.Glass.Autofac.Mvc/Pipelines/Factories/Providers/MvcLifetimeScopeProvider.cs create mode 100644 Jabberwocky.Glass.Autofac.WebApi/Jabberwocky.Glass.Autofac.WebApi.csproj create mode 100644 Jabberwocky.Glass.Autofac.WebApi/Pipelines/Factories/Providers/WebApiLifetimeScopeProvider.cs create mode 100644 Jabberwocky.Glass.Autofac.WebApi/Properties/AssemblyInfo.cs create mode 100644 Jabberwocky.Glass.Autofac.WebApi/packages.config create mode 100644 Jabberwocky.Glass.Autofac/Pipelines/Factories/DefaultLifetimeScopeFactory.cs create mode 100644 Jabberwocky.Glass.Autofac/Pipelines/Factories/ILifetimeScopeFactory.cs create mode 100644 Jabberwocky.Glass.Autofac/Pipelines/Factories/Providers/ILifetimeScopeProvider.cs diff --git a/Jabberwocky.Glass.Autofac.Mvc/Jabberwocky.Glass.Autofac.Mvc.csproj b/Jabberwocky.Glass.Autofac.Mvc/Jabberwocky.Glass.Autofac.Mvc.csproj index ec9a38b..c9fc660 100644 --- a/Jabberwocky.Glass.Autofac.Mvc/Jabberwocky.Glass.Autofac.Mvc.csproj +++ b/Jabberwocky.Glass.Autofac.Mvc/Jabberwocky.Glass.Autofac.Mvc.csproj @@ -35,6 +35,10 @@ ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + ..\packages\Autofac.Mvc5.3.3.3\lib\net45\Autofac.Integration.Mvc.dll + True + ..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll @@ -103,6 +107,7 @@ + @@ -127,6 +132,7 @@ Jabberwocky.Glass + diff --git a/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Factories/Providers/MvcLifetimeScopeProvider.cs b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Factories/Providers/MvcLifetimeScopeProvider.cs new file mode 100644 index 0000000..ce8b9db --- /dev/null +++ b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Factories/Providers/MvcLifetimeScopeProvider.cs @@ -0,0 +1,14 @@ +using Autofac; +using Autofac.Integration.Mvc; +using ILifetimeScopeProvider = Jabberwocky.Glass.Autofac.Pipelines.Factories.Providers.ILifetimeScopeProvider; + +namespace Jabberwocky.Glass.Autofac.Mvc.Pipelines.Factories.Providers +{ + public class MvcLifetimeScopeProvider : ILifetimeScopeProvider + { + public ILifetimeScope GetLifetimeScope() + { + return AutofacDependencyResolver.Current?.RequestLifetimeScope; + } + } +} diff --git a/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelFromViewProcessor.cs b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelFromViewProcessor.cs index 6e22a96..a6fda69 100644 --- a/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelFromViewProcessor.cs +++ b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelFromViewProcessor.cs @@ -34,7 +34,7 @@ public GetModelFromViewProcessor(IModelCacheManager modelCacheManager, IViewMode /// public string ContextName { get; set; } - protected override void Run(GetModelArgs args) + protected internal override void Run(GetModelArgs args) { if (!IsValidForProcessing(args)) { diff --git a/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelProcessor.cs b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelProcessor.cs index 374eda5..d7d9d0c 100644 --- a/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelProcessor.cs +++ b/Jabberwocky.Glass.Autofac.Mvc/Pipelines/Processors/GetModelProcessor.cs @@ -42,7 +42,7 @@ public GetModelProcessor(IViewModelFactory viewModelFactory) _viewModelFactory = viewModelFactory; } - protected override void Run(GetModelArgs args) + protected internal override void Run(GetModelArgs args) { if (args.Result != null) return; diff --git a/Jabberwocky.Glass.Autofac.Mvc/packages.config b/Jabberwocky.Glass.Autofac.Mvc/packages.config index 3093bd7..258a91c 100644 --- a/Jabberwocky.Glass.Autofac.Mvc/packages.config +++ b/Jabberwocky.Glass.Autofac.Mvc/packages.config @@ -1,6 +1,7 @@  + diff --git a/Jabberwocky.Glass.Autofac.WebApi/Jabberwocky.Glass.Autofac.WebApi.csproj b/Jabberwocky.Glass.Autofac.WebApi/Jabberwocky.Glass.Autofac.WebApi.csproj new file mode 100644 index 0000000..18dc945 --- /dev/null +++ b/Jabberwocky.Glass.Autofac.WebApi/Jabberwocky.Glass.Autofac.WebApi.csproj @@ -0,0 +1,87 @@ + + + + + Debug + AnyCPU + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE} + Library + Properties + Jabberwocky.Glass.Autofac.WebApi + Jabberwocky.Glass.Autofac.WebApi + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True + + + ..\packages\Autofac.WebApi2.3.3.3\lib\net45\Autofac.Integration.WebApi.dll + True + + + ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + True + + + + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll + True + + + + + + + + + + + + + + + {ea620f62-8d08-4031-bac4-1c60d5c5cbc9} + Jabberwocky.Glass.Autofac + + + + + + + + \ No newline at end of file diff --git a/Jabberwocky.Glass.Autofac.WebApi/Pipelines/Factories/Providers/WebApiLifetimeScopeProvider.cs b/Jabberwocky.Glass.Autofac.WebApi/Pipelines/Factories/Providers/WebApiLifetimeScopeProvider.cs new file mode 100644 index 0000000..46cf86e --- /dev/null +++ b/Jabberwocky.Glass.Autofac.WebApi/Pipelines/Factories/Providers/WebApiLifetimeScopeProvider.cs @@ -0,0 +1,19 @@ +using System.Web.Http; +using System.Web.Http.Dependencies; +using Autofac; +using Autofac.Integration.WebApi; +using Jabberwocky.Glass.Autofac.Pipelines.Factories.Providers; + +namespace Jabberwocky.Glass.Autofac.WebApi.Pipelines.Factories.Providers +{ + public class WebApiLifetimeScopeProvider : ILifetimeScopeProvider + { + public ILifetimeScope GetLifetimeScope() + { + // If using the Autofac.WebApi integration package, this dependency should be of type 'AutofacWebApiDependencyResolver' + var resolver = GlobalConfiguration.Configuration.DependencyResolver as IDependencyScope; + + return resolver?.GetRequestLifetimeScope(); + } + } +} diff --git a/Jabberwocky.Glass.Autofac.WebApi/Properties/AssemblyInfo.cs b/Jabberwocky.Glass.Autofac.WebApi/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b671ddf --- /dev/null +++ b/Jabberwocky.Glass.Autofac.WebApi/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jabberwocky.Glass.Autofac.WebApi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Jabberwocky.Glass.Autofac.WebApi")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("86b4e810-dca7-4510-ba2b-ec1dda9cb7fe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Jabberwocky.Glass.Autofac.WebApi/packages.config b/Jabberwocky.Glass.Autofac.WebApi/packages.config new file mode 100644 index 0000000..d41c1fe --- /dev/null +++ b/Jabberwocky.Glass.Autofac.WebApi/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Jabberwocky.Glass.Autofac/Extensions/SitecorePipelineRegistrationExtensions.cs b/Jabberwocky.Glass.Autofac/Extensions/SitecorePipelineRegistrationExtensions.cs index cc76151..1f72d7f 100644 --- a/Jabberwocky.Glass.Autofac/Extensions/SitecorePipelineRegistrationExtensions.cs +++ b/Jabberwocky.Glass.Autofac/Extensions/SitecorePipelineRegistrationExtensions.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Autofac; +using Jabberwocky.Glass.Autofac.Pipelines.Factories; +using Jabberwocky.Glass.Autofac.Pipelines.Factories.Providers; using Jabberwocky.Glass.Autofac.Pipelines.Processors; namespace Jabberwocky.Glass.Autofac.Extensions @@ -14,6 +17,7 @@ public static class SitecorePipelineRegistrationExtensions private const string MasterDatabaseName = "master"; private const string JabberwockyMvcDll = "Jabberwocky.Glass.Autofac.Mvc"; + private const string JabberwockyWebApiDll = "Jabberwocky.Glass.Autofac.WebApi"; /// /// Registers any custom Sitecore Pipeline Processors that implement the IProcessor interface @@ -38,10 +42,15 @@ public static ContainerBuilder RegisterProcessors(this ContainerBuilder builder, /// public static ContainerBuilder RegisterProcessors(this ContainerBuilder builder, params Assembly[] assemblies) { - var asm = new[] {TryLoadAssembly(JabberwockyMvcDll)}.Concat(assemblies).Where(a => a != null).Distinct().ToArray(); + var asm = new[] { JabberwockyMvcDll, JabberwockyWebApiDll }.Select(TryLoadAssembly).Concat(assemblies).Where(a => a != null).Distinct().ToArray(); + // Register processors builder.RegisterAssemblyTypes(asm).AsClosedTypesOf(typeof(IProcessor<>)); - + + // Register internals for Lifetime Scope resolution + builder.RegisterAssemblyTypes(asm).AssignableTo().As(); + builder.Register(c => new DefaultLifetimeScopeFactory(c.Resolve>())).As(); + return builder; } diff --git a/Jabberwocky.Glass.Autofac/Jabberwocky.Glass.Autofac.csproj b/Jabberwocky.Glass.Autofac/Jabberwocky.Glass.Autofac.csproj index b28b2c1..1a61931 100644 --- a/Jabberwocky.Glass.Autofac/Jabberwocky.Glass.Autofac.csproj +++ b/Jabberwocky.Glass.Autofac/Jabberwocky.Glass.Autofac.csproj @@ -82,6 +82,9 @@ + + + diff --git a/Jabberwocky.Glass.Autofac/Pipelines/Factories/AutofacProcessorFactory.cs b/Jabberwocky.Glass.Autofac/Pipelines/Factories/AutofacProcessorFactory.cs index 54bd68f..9414103 100644 --- a/Jabberwocky.Glass.Autofac/Pipelines/Factories/AutofacProcessorFactory.cs +++ b/Jabberwocky.Glass.Autofac/Pipelines/Factories/AutofacProcessorFactory.cs @@ -14,13 +14,13 @@ public class AutofacProcessorFactory : IFactory { protected static IContainer Container => AutofacConfig.ServiceLocator; - public virtual object GetObject(string identifier) + public virtual object GetObject(string identifier) { var type = ResolveType(identifier); if (type == null) return null; // Includes Pipeline specific registrations that override existing defaults - var scope = Container.BeginLifetimeScope(ConfigureRegistrationOverrides); + var scope = CreateLifetimeScope(); try { var processor = scope.Resolve(type); @@ -43,6 +43,20 @@ public virtual object GetObject(string identifier) return null; } + protected virtual ILifetimeScope CreateLifetimeScope() + { + if (Container == null) + throw new InvalidOperationException($"The '{nameof(Container)}' property was null. Ensure that the AutofacConfig.{nameof(AutofacConfig.ServiceLocator)} has been assigned."); + + using (var scope = Container.BeginLifetimeScope()) + { + var existingScopeProvider = scope.ResolveOptional(); + var scopeResolver = existingScopeProvider?.GetCurrentLifetimeScope() ?? Container; + + return scopeResolver.BeginLifetimeScope(ConfigureRegistrationOverrides); + } + } + protected virtual void ConfigureRegistrationOverrides(ContainerBuilder builder) { builder.RegisterSitecorePipelineServices(); diff --git a/Jabberwocky.Glass.Autofac/Pipelines/Factories/DefaultLifetimeScopeFactory.cs b/Jabberwocky.Glass.Autofac/Pipelines/Factories/DefaultLifetimeScopeFactory.cs new file mode 100644 index 0000000..aeae513 --- /dev/null +++ b/Jabberwocky.Glass.Autofac/Pipelines/Factories/DefaultLifetimeScopeFactory.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autofac; +using Jabberwocky.Glass.Autofac.Pipelines.Factories.Providers; + +namespace Jabberwocky.Glass.Autofac.Pipelines.Factories +{ + internal class DefaultLifetimeScopeFactory : ILifetimeScopeFactory + { + private readonly IEnumerable _scopeProviders; + + internal DefaultLifetimeScopeFactory(IEnumerable scopeProviders) + { + if (scopeProviders == null) throw new ArgumentNullException(nameof(scopeProviders)); + _scopeProviders = scopeProviders; + } + + public ILifetimeScope GetCurrentLifetimeScope() + { + return _scopeProviders + .Select(provider => provider.GetLifetimeScope()) + .FirstOrDefault(scope => scope != null); + } + } +} diff --git a/Jabberwocky.Glass.Autofac/Pipelines/Factories/ILifetimeScopeFactory.cs b/Jabberwocky.Glass.Autofac/Pipelines/Factories/ILifetimeScopeFactory.cs new file mode 100644 index 0000000..f58bc10 --- /dev/null +++ b/Jabberwocky.Glass.Autofac/Pipelines/Factories/ILifetimeScopeFactory.cs @@ -0,0 +1,9 @@ +using Autofac; + +namespace Jabberwocky.Glass.Autofac.Pipelines.Factories +{ + public interface ILifetimeScopeFactory + { + ILifetimeScope GetCurrentLifetimeScope(); + } +} diff --git a/Jabberwocky.Glass.Autofac/Pipelines/Factories/Providers/ILifetimeScopeProvider.cs b/Jabberwocky.Glass.Autofac/Pipelines/Factories/Providers/ILifetimeScopeProvider.cs new file mode 100644 index 0000000..b616525 --- /dev/null +++ b/Jabberwocky.Glass.Autofac/Pipelines/Factories/Providers/ILifetimeScopeProvider.cs @@ -0,0 +1,9 @@ +using Autofac; + +namespace Jabberwocky.Glass.Autofac.Pipelines.Factories.Providers +{ + internal interface ILifetimeScopeProvider + { + ILifetimeScope GetLifetimeScope(); + } +} diff --git a/Jabberwocky.Glass.Autofac/Properties/AssemblyInfo.cs b/Jabberwocky.Glass.Autofac/Properties/AssemblyInfo.cs index e961d2c..32583b0 100644 --- a/Jabberwocky.Glass.Autofac/Properties/AssemblyInfo.cs +++ b/Jabberwocky.Glass.Autofac/Properties/AssemblyInfo.cs @@ -34,3 +34,6 @@ // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.1.0")] [assembly: AssemblyFileVersion("1.0.1.0")] + +[assembly: InternalsVisibleTo("Jabberwocky.Glass.Autofac.Mvc")] +[assembly: InternalsVisibleTo("Jabberwocky.Glass.Autofac.WebApi")] diff --git a/Jabberwocky.sln b/Jabberwocky.sln index e9595cd..ed0f350 100644 --- a/Jabberwocky.sln +++ b/Jabberwocky.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jabberwocky.Core", "Jabberwocky.Core\Jabberwocky.Core.csproj", "{79F22272-B90E-4461-BAEE-92AE1A6C28BC}" EndProject @@ -56,6 +56,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{338A9D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jabberwocky.Autofac.Extras.MiniProfiler", "Jabberwocky.Autofac.Extras.MiniProfiler\Jabberwocky.Autofac.Extras.MiniProfiler.csproj", "{44DB88AB-C38E-4CAE-ADA0-BC64778A1D4A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jabberwocky.Glass.Autofac.WebApi", "Jabberwocky.Glass.Autofac.WebApi\Jabberwocky.Glass.Autofac.WebApi.csproj", "{86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -130,6 +132,10 @@ Global {44DB88AB-C38E-4CAE-ADA0-BC64778A1D4A}.Debug|Any CPU.Build.0 = Debug|Any CPU {44DB88AB-C38E-4CAE-ADA0-BC64778A1D4A}.Release|Any CPU.ActiveCfg = Release|Any CPU {44DB88AB-C38E-4CAE-ADA0-BC64778A1D4A}.Release|Any CPU.Build.0 = Release|Any CPU + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -155,5 +161,6 @@ Global {315DCFFB-97B4-43E5-9ECF-3EDC7E32C93F} = {FF1D41BA-5DE4-49CC-8CFF-08B1BF700C3D} {338A9D71-3ED1-4E69-AC1B-E5033846B3A4} = {FF1D41BA-5DE4-49CC-8CFF-08B1BF700C3D} {44DB88AB-C38E-4CAE-ADA0-BC64778A1D4A} = {338A9D71-3ED1-4E69-AC1B-E5033846B3A4} + {86B4E810-DCA7-4510-BA2B-EC1DDA9CB7FE} = {FF1D41BA-5DE4-49CC-8CFF-08B1BF700C3D} EndGlobalSection EndGlobal