mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-14 19:04:51 +08:00
PERF: CreateWorkContextScope shouldn't call InstancePerMatchingLifetimeScope
http://orchard.codeplex.com/workitem/16869 CreateWorkContextScope now creates a child container with no alteration to the component registry WorkContextModule added to group the related set of component registrations HttpContextBase still injectable, but it's exposed in a way that doesn't require updating the child container per request --HG-- branch : perf
This commit is contained in:
@@ -46,7 +46,7 @@ namespace Orchard.Core.Tests.Routable.Services {
|
||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||
builder.RegisterInstance(new Mock<IContentDisplay>().Object);
|
||||
builder.RegisterType<StubHttpContextAccessor>().As<IHttpContextAccessor>();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
|
||||
|
||||
builder.RegisterType<ThingHandler>().As<IContentHandler>();
|
||||
|
@@ -22,7 +22,7 @@ namespace Orchard.Tests.Environment {
|
||||
}
|
||||
|
||||
protected override void Register(ContainerBuilder builder) {
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterAutoMocking();
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<ShellContextFactory>().As<IShellContextFactory>();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterAutoMocking(Moq.MockBehavior.Strict);
|
||||
_container = builder.Build();
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ namespace Orchard.Tests.Environment.State {
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<DefaultProcessingEngine>().As<IProcessingEngine>();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterAutoMocking();
|
||||
_container = builder.Build();
|
||||
|
||||
|
@@ -51,7 +51,7 @@ namespace Orchard.Tests.Localization {
|
||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||
builder.RegisterInstance(new Mock<IContentDisplay>().Object);
|
||||
builder.RegisterType<StubHttpContextAccessor>().As<IHttpContextAccessor>();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
|
||||
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
|
||||
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
|
||||
|
@@ -36,7 +36,7 @@ namespace Orchard.Tests.Mvc.Routes {
|
||||
rootBuilder.Register(ctx => _routes);
|
||||
rootBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
rootBuilder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
|
||||
rootBuilder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>().InstancePerMatchingLifetimeScope("shell");
|
||||
rootBuilder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>().InstancePerMatchingLifetimeScope("shell");
|
||||
rootBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>();
|
||||
|
||||
_rootContainer = rootBuilder.Build();
|
||||
|
@@ -12,7 +12,7 @@ namespace Orchard.Tests.Tasks {
|
||||
public class SweepGeneratorTests : ContainerTestBase {
|
||||
protected override void Register(ContainerBuilder builder) {
|
||||
builder.RegisterAutoMocking(MockBehavior.Loose);
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<SweepGenerator>();
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ namespace Orchard.Tests.UI {
|
||||
|
||||
protected override void Register(ContainerBuilder builder) {
|
||||
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<LayoutWorkContext>().As<IWorkContextStateProvider>();
|
||||
|
@@ -45,6 +45,8 @@ namespace Orchard.Setup {
|
||||
// standard services needed in setup mode
|
||||
builder.RegisterModule(new MvcModule());
|
||||
builder.RegisterModule(new CommandModule());
|
||||
builder.RegisterModule(new WorkContextModule());
|
||||
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ModelBinderPublisher>().As<IModelBinderPublisher>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<WebFormViewEngineProvider>().As<IViewEngineProvider>().As<IShapeTemplateViewEngine>().InstancePerLifetimeScope();
|
||||
@@ -58,7 +60,7 @@ namespace Orchard.Setup {
|
||||
builder.RegisterType<DataServicesProviderFactory>().As<IDataServicesProviderFactory>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<DefaultCommandManager>().As<ICommandManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<HelpCommand>().As<ICommandHandler>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>().InstancePerMatchingLifetimeScope("shell");
|
||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>().InstancePerMatchingLifetimeScope("shell");
|
||||
builder.RegisterType<ResourceManifest>().As<IResourceManifestProvider>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ResourceManager>().As<IResourceManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<ResourceFilter>().As<IFilterProvider>().InstancePerLifetimeScope();
|
||||
|
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Autofac;
|
||||
using Orchard.Mvc;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public class DefaultWorkContextAccessor : IWorkContextAccessor {
|
||||
public class WorkContextAccessor : IWorkContextAccessor {
|
||||
readonly ILifetimeScope _lifetimeScope;
|
||||
|
||||
readonly IHttpContextAccessor _httpContextAccessor;
|
||||
@@ -18,7 +16,7 @@ namespace Orchard.Environment {
|
||||
[ThreadStatic]
|
||||
static ConcurrentDictionary<object, WorkContext> _threadStaticContexts;
|
||||
|
||||
public DefaultWorkContextAccessor(
|
||||
public WorkContextAccessor(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ILifetimeScope lifetimeScope) {
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
@@ -39,36 +37,23 @@ namespace Orchard.Environment {
|
||||
}
|
||||
|
||||
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
|
||||
var workLifetime = _lifetimeScope.BeginLifetimeScope("work");
|
||||
workLifetime.Resolve<WorkContextProperty<HttpContextBase>>().Value = httpContext;
|
||||
|
||||
var workLifetime = SpawnWorkLifetime(builder => {
|
||||
builder.Register(ctx => httpContext)
|
||||
.As<HttpContextBase>();
|
||||
|
||||
builder.Register(ctx => new WorkContextImplementation(ctx))
|
||||
.As<WorkContext>()
|
||||
.InstancePerMatchingLifetimeScope("work");
|
||||
});
|
||||
return new HttpContextScopeImplementation(
|
||||
workLifetime,
|
||||
httpContext,
|
||||
_workContextKey);
|
||||
}
|
||||
|
||||
|
||||
public IWorkContextScope CreateWorkContextScope() {
|
||||
var httpContext = _httpContextAccessor.Current();
|
||||
if (httpContext != null)
|
||||
return CreateWorkContextScope(httpContext);
|
||||
|
||||
var workLifetime = SpawnWorkLifetime(builder => {
|
||||
builder.Register(ctx => httpContext)
|
||||
.As<HttpContextBase>();
|
||||
|
||||
builder.Register(ctx => new WorkContextImplementation(ctx))
|
||||
.As<WorkContext>()
|
||||
.InstancePerMatchingLifetimeScope("work");
|
||||
});
|
||||
return new ThreadStaticScopeImplementation(
|
||||
workLifetime,
|
||||
_lifetimeScope.BeginLifetimeScope("work"),
|
||||
EnsureThreadStaticContexts(),
|
||||
_workContextKey);
|
||||
}
|
||||
@@ -77,49 +62,6 @@ namespace Orchard.Environment {
|
||||
return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary<object, WorkContext>());
|
||||
}
|
||||
|
||||
private ILifetimeScope SpawnWorkLifetime(Action<ContainerBuilder> configurationAction) {
|
||||
return _lifetimeScope.BeginLifetimeScope("work", configurationAction);
|
||||
}
|
||||
|
||||
class WorkContextImplementation : WorkContext {
|
||||
readonly IComponentContext _componentContext;
|
||||
readonly ConcurrentDictionary<string, Func<object>> _stateResolvers = new ConcurrentDictionary<string, Func<object>>();
|
||||
readonly IEnumerable<IWorkContextStateProvider> _workContextStateProviders;
|
||||
|
||||
public WorkContextImplementation(IComponentContext componentContext) {
|
||||
_componentContext = componentContext;
|
||||
_workContextStateProviders = componentContext.Resolve<IEnumerable<IWorkContextStateProvider>>();
|
||||
}
|
||||
|
||||
public override T Resolve<T>() {
|
||||
return _componentContext.Resolve<T>();
|
||||
}
|
||||
|
||||
public override bool TryResolve<T>(out T service) {
|
||||
return _componentContext.TryResolve(out service);
|
||||
}
|
||||
|
||||
public override T GetState<T>(string name) {
|
||||
var resolver = _stateResolvers.GetOrAdd(name, FindResolverForState<T>);
|
||||
return (T)resolver();
|
||||
}
|
||||
|
||||
Func<object> FindResolverForState<T>(string name) {
|
||||
var resolver = _workContextStateProviders.Select(wcsp => wcsp.Get<T>(name))
|
||||
.FirstOrDefault(value => !Equals(value, default(T)));
|
||||
|
||||
if (resolver == null) {
|
||||
return () => default(T);
|
||||
}
|
||||
return () => resolver(this);
|
||||
}
|
||||
|
||||
|
||||
public override void SetState<T>(string name, T value) {
|
||||
_stateResolvers[name] = () => value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HttpContextScopeImplementation : IWorkContextScope {
|
||||
readonly WorkContext _workContext;
|
45
src/Orchard/Environment/WorkContextImplementation.cs
Normal file
45
src/Orchard/Environment/WorkContextImplementation.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
class WorkContextImplementation : WorkContext {
|
||||
readonly IComponentContext _componentContext;
|
||||
readonly ConcurrentDictionary<string, Func<object>> _stateResolvers = new ConcurrentDictionary<string, Func<object>>();
|
||||
readonly IEnumerable<IWorkContextStateProvider> _workContextStateProviders;
|
||||
|
||||
public WorkContextImplementation(IComponentContext componentContext) {
|
||||
_componentContext = componentContext;
|
||||
_workContextStateProviders = componentContext.Resolve<IEnumerable<IWorkContextStateProvider>>();
|
||||
}
|
||||
|
||||
public override T Resolve<T>() {
|
||||
return _componentContext.Resolve<T>();
|
||||
}
|
||||
|
||||
public override bool TryResolve<T>(out T service) {
|
||||
return _componentContext.TryResolve(out service);
|
||||
}
|
||||
|
||||
public override T GetState<T>(string name) {
|
||||
var resolver = _stateResolvers.GetOrAdd(name, FindResolverForState<T>);
|
||||
return (T)resolver();
|
||||
}
|
||||
|
||||
Func<object> FindResolverForState<T>(string name) {
|
||||
var resolver = Enumerable.FirstOrDefault(_workContextStateProviders.Select(wcsp => wcsp.Get<T>(name)), value => !Equals(value, default(T)));
|
||||
|
||||
if (resolver == null) {
|
||||
return () => default(T);
|
||||
}
|
||||
return () => resolver(this);
|
||||
}
|
||||
|
||||
|
||||
public override void SetState<T>(string name, T value) {
|
||||
_stateResolvers[name] = () => value;
|
||||
}
|
||||
}
|
||||
}
|
24
src/Orchard/Environment/WorkContextModule.cs
Normal file
24
src/Orchard/Environment/WorkContextModule.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Web;
|
||||
using Autofac;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public class WorkContextModule : Module {
|
||||
protected override void Load(ContainerBuilder builder) {
|
||||
builder.RegisterType<WorkContextAccessor>()
|
||||
.As<IWorkContextAccessor>()
|
||||
.InstancePerMatchingLifetimeScope("shell");
|
||||
|
||||
builder.Register(ctx => new WorkContextImplementation(ctx))
|
||||
.As<WorkContext>()
|
||||
.InstancePerMatchingLifetimeScope("work");
|
||||
|
||||
builder.RegisterType<WorkContextProperty<HttpContextBase>>()
|
||||
.As<WorkContextProperty<HttpContextBase>>()
|
||||
.InstancePerMatchingLifetimeScope("work");
|
||||
|
||||
builder.Register(ctx => ctx.Resolve<WorkContextProperty<HttpContextBase>>().Value)
|
||||
.As<HttpContextBase>()
|
||||
.InstancePerDependency();
|
||||
}
|
||||
}
|
||||
}
|
5
src/Orchard/Environment/WorkContextProperty.cs
Normal file
5
src/Orchard/Environment/WorkContextProperty.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.Environment {
|
||||
class WorkContextProperty<T> {
|
||||
public T Value { get; set; }
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Orchard {
|
||||
public interface IWorkContextAccessor : ISingletonDependency {
|
||||
public interface IWorkContextAccessor {
|
||||
WorkContext GetContext(HttpContextBase httpContext);
|
||||
IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext);
|
||||
|
||||
|
@@ -158,6 +158,9 @@
|
||||
<Compile Include="Environment\Extensions\Loaders\RawThemeExtensionLoader.cs" />
|
||||
<Compile Include="Environment\Features\FeatureManager.cs" />
|
||||
<Compile Include="Environment\IAssemblyLoader.cs" />
|
||||
<Compile Include="Environment\WorkContextImplementation.cs" />
|
||||
<Compile Include="Environment\WorkContextModule.cs" />
|
||||
<Compile Include="Environment\WorkContextProperty.cs" />
|
||||
<Compile Include="Localization\Services\CurrentCultureWorkContext.cs" />
|
||||
<Compile Include="Localization\Services\DefaultLocalizedStringManager.cs" />
|
||||
<Compile Include="Localization\Services\ILocalizedStringManager.cs" />
|
||||
@@ -419,7 +422,7 @@
|
||||
<Compile Include="DisplayManagement\Implementation\IDisplayManager.cs" />
|
||||
<Compile Include="DisplayManagement\IShapeFactory.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\Interfaces.cs" />
|
||||
<Compile Include="Environment\DefaultWorkContextAccessor.cs" />
|
||||
<Compile Include="Environment\WorkContextAccessor.cs" />
|
||||
<Compile Include="Environment\IHostLocalRestart.cs" />
|
||||
<Compile Include="Environment\IShellContainerRegistrations.cs" />
|
||||
<Compile Include="FileSystems\Dependencies\DynamicModuleVirtualPathProvider.cs" />
|
||||
|
Reference in New Issue
Block a user