Continued adjustments

Removing direct references to IContainer and IContainerProvider from within components
Fixing broken tests

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-09-02 22:14:07 -07:00
parent 6a5536dd32
commit c4e1cbeb53
18 changed files with 104 additions and 95 deletions

View File

@@ -36,7 +36,7 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
public void AllDriversShouldBeCalled() {
var driver1 = new Mock<IContentPartDriver>();
var driver2 = new Mock<IContentPartDriver>();
var builder = new ContainerUpdater();
var builder = new ContainerBuilder();
builder.RegisterInstance(driver1.Object);
builder.RegisterInstance(driver2.Object);
builder.Update(_container);
@@ -52,7 +52,7 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
[Test]
public void TestDriverCanAddDisplay() {
var driver = new StubPartDriver();
var builder = new ContainerUpdater();
var builder = new ContainerBuilder();
builder.RegisterInstance(driver).As<IContentPartDriver>();
builder.Update(_container);

View File

@@ -50,7 +50,6 @@ namespace Orchard.Tests.Environment {
_container = OrchardStarter.CreateHostContainer(
builder => {
builder.RegisterInstance(new StubShellSettingsLoader()).As<IShellSettingsManager>();
builder.RegisterType<StubContainerProvider>().As<IContainerProvider>().InstancePerLifetimeScope();
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
builder.RegisterType<ModelBinderPublisher>().As<IModelBinderPublisher>();
builder.RegisterType<ShellContextFactory>().As<IShellContextFactory>();
@@ -81,9 +80,6 @@ namespace Orchard.Tests.Environment {
_container.Mock<IOrchardShellEvents>()
.Setup(e => e.Activated());
var updater = new ContainerUpdater();
updater.RegisterInstance(_container).SingleInstance();
updater.Update(_lifetime);
}
public class StubExtensionManager : IExtensionManager {

View File

@@ -1,4 +1,5 @@
using Autofac;
using System.Web;
using Autofac;
using Autofac.Core.Registration;
using Moq;
using NUnit.Framework;
@@ -8,6 +9,7 @@ using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.ShellBuilders.Models;
using Orchard.Mvc;
using Orchard.Tests.Utility;
namespace Orchard.Tests.Environment.ShellBuilders {
@@ -19,6 +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.RegisterAutoMocking(Moq.MockBehavior.Strict);
_container = builder.Build();
}
@@ -46,6 +49,10 @@ namespace Orchard.Tests.Environment.ShellBuilders {
.Setup(x => x.GetShellDescriptor())
.Returns(descriptor);
_container.Mock<IHttpContextAccessor>()
.Setup(x => x.Current())
.Returns(default(HttpContextBase));
var factory = _container.Resolve<IShellContextFactory>();
var context = factory.CreateShellContext(settings);

View File

@@ -1,13 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.ShellBuilders;
using Orchard.Environment.State;
using Orchard.Environment.Descriptor.Models;
using Orchard.Events;
using Orchard.Mvc;
using Orchard.Tests.Utility;
namespace Orchard.Tests.Environment.State {
@@ -20,6 +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.RegisterAutoMocking();
_container = builder.Build();
@@ -32,6 +36,9 @@ namespace Orchard.Tests.Environment.State {
_container.Mock<IShellContextFactory>()
.Setup(x => x.CreateDescribedContext(_shellContext.Settings, _shellContext.Descriptor))
.Returns(_shellContext);
_container.Mock<IHttpContextAccessor>()
.Setup(x=>x.Current())
.Returns(default(HttpContextBase));
}

View File

@@ -11,6 +11,7 @@ using Moq;
using NUnit.Framework;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Mvc;
using Orchard.Mvc.Routes;
using Orchard.Tests.Stubs;
using Orchard.Tests.Utility;
@@ -35,16 +36,20 @@ 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<HttpContextAccessor>().As<IHttpContextAccessor>();
_rootContainer = rootBuilder.Build();
_containerA = _rootContainer.BeginLifetimeScope(
"shell",
builder => {
builder.Register(ctx => _settingsA);
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().InstancePerLifetimeScope();
});
_containerB = _rootContainer.BeginLifetimeScope(
"shell",
builder => {
builder.Register(ctx => _settingsB);
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().InstancePerLifetimeScope();

View File

@@ -2,42 +2,43 @@
using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.Environment;
using Orchard.Mvc;
using Orchard.Tasks;
using Orchard.Tests.Utility;
namespace Orchard.Tests.Tasks {
[TestFixture]
public class SweepGeneratorTests {
public class SweepGeneratorTests : ContainerTestBase {
protected override void Register(ContainerBuilder builder) {
builder.RegisterAutoMocking(MockBehavior.Loose);
builder.RegisterType<DefaultWorkContextAccessor>().As<IWorkContextAccessor>();
builder.RegisterType<SweepGenerator>();
}
[Test]
public void DoWorkShouldSendHeartbeatToTaskManager() {
var taskManager = new Mock<IBackgroundService>();
var builder = new ContainerBuilder();
builder.RegisterInstance(taskManager.Object);
var container = builder.Build();
var heartbeatSource = new SweepGenerator(container);
var heartbeatSource = _container.Resolve<SweepGenerator>();
heartbeatSource.DoWork();
taskManager.Verify(x => x.Sweep(), Times.Once());
_container.Resolve<Mock<IBackgroundService>>()
.Verify(x => x.Sweep(), Times.Once());
}
[Test]
public void ActivatedEventShouldStartTimer() {
var taskManager = new Mock<IBackgroundService>();
var builder = new ContainerBuilder();
builder.RegisterInstance(taskManager.Object);
var container = builder.Build();
var heartbeatSource = _container.Resolve<SweepGenerator>();
heartbeatSource.Interval = TimeSpan.FromMilliseconds(25);
var heartbeatSource = new SweepGenerator(container) {
Interval = TimeSpan.FromMilliseconds(25)
};
_container.Resolve<Mock<IBackgroundService>>()
.Verify(x => x.Sweep(), Times.Never());
taskManager.Verify(x => x.Sweep(), Times.Never());
heartbeatSource.Activated();
System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(80));
heartbeatSource.Terminating();
taskManager.Verify(x => x.Sweep(), Times.AtLeastOnce());
_container.Resolve<Mock<IBackgroundService>>()
.Verify(x => x.Sweep(), Times.AtLeastOnce());
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using Autofac;
using Autofac.Core;
namespace Orchard.Environment.AutofacUtil {
public class ContainerUpdater : ContainerBuilder {
readonly ICollection<Action<IComponentRegistry>> _configurationActions = new List<Action<IComponentRegistry>>();
public override void RegisterCallback(Action<IComponentRegistry> configurationAction) {
_configurationActions.Add(configurationAction);
}
public void Update(IContainer container) {
foreach (var action in _configurationActions)
action(container.ComponentRegistry);
}
public void Update(ILifetimeScope container) {
foreach (var action in _configurationActions)
action(container.ComponentRegistry);
}
}
}

View File

@@ -2,13 +2,10 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Web;
namespace Orchard.Environment {
//IContainerProvider
public class DefaultOrchardHostContainer : IOrchardHostContainer, IMvcServiceLocator {
private readonly IContainer _container;

View File

@@ -15,7 +15,7 @@ namespace Orchard.Environment {
readonly object _workContextKey = new object();
[ThreadStatic]
static readonly ConcurrentDictionary<object, WorkContext> _threadStaticContexts = new ConcurrentDictionary<object, WorkContext>();
static ConcurrentDictionary<object, WorkContext> _threadStaticContexts;
public DefaultWorkContextAccessor(
IHttpContextAccessor httpContextAccessor,
@@ -36,7 +36,7 @@ namespace Orchard.Environment {
return GetContext(httpContext);
WorkContext workContext;
return _threadStaticContexts.TryGetValue(_workContextKey, out workContext) ? workContext : null;
return EnsureThreadStaticContexts().TryGetValue(_workContextKey, out workContext) ? workContext : null;
}
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
@@ -71,10 +71,14 @@ namespace Orchard.Environment {
});
return new ThreadStaticScopeImplementation(
workLifetime,
_threadStaticContexts,
EnsureThreadStaticContexts(),
_workContextKey);
}
static ConcurrentDictionary<object, WorkContext> EnsureThreadStaticContexts() {
return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary<object, WorkContext>());
}
private ILifetimeScope SpawnWorkLifetime(Action<ContainerBuilder> configurationAction) {
return _lifetimeScope.BeginLifetimeScope("work", configurationAction);
}
@@ -87,8 +91,8 @@ namespace Orchard.Environment {
_componentContext = componentContext;
}
public override T Service<T>() {
throw new NotImplementedException();
public override T Resolve<T>() {
return _componentContext.Resolve<T>();
}
public override T State<T>() {
@@ -118,7 +122,7 @@ namespace Orchard.Environment {
}
public TService Resolve<TService>() {
return WorkContext.Service<TService>();
return WorkContext.Resolve<TService>();
}
}
@@ -145,7 +149,7 @@ namespace Orchard.Environment {
}
public TService Resolve<TService>() {
return WorkContext.Service<TService>();
return WorkContext.Resolve<TService>();
}
}
}

View File

@@ -22,6 +22,7 @@ using Orchard.FileSystems.Dependencies;
using Orchard.FileSystems.VirtualPath;
using Orchard.FileSystems.WebSite;
using Orchard.Logging;
using Orchard.Mvc;
using Orchard.Services;
namespace Orchard.Environment {
@@ -43,6 +44,7 @@ namespace Orchard.Environment {
builder.RegisterType<AppDataFolderRoot>().As<IAppDataFolderRoot>().SingleInstance();
builder.RegisterType<DefaultExtensionCompiler>().As<IExtensionCompiler>().SingleInstance();
builder.RegisterType<DefaultProjectFileParser>().As<IProjectFileParser>().SingleInstance();
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
@@ -60,23 +62,18 @@ namespace Orchard.Environment {
{
builder.RegisterType<ShellDescriptorCache>().As<IShellDescriptorCache>().SingleInstance();
builder.RegisterType<CompositionStrategy>()
.As<ICompositionStrategy>()
.SingleInstance();
builder.RegisterType<CompositionStrategy>().As<ICompositionStrategy>().SingleInstance();
{
builder.RegisterType<ShellContainerRegistrations>().As<IShellContainerRegistrations>().SingleInstance();
builder.RegisterType<ExtensionLoaderCoordinator>().As<IExtensionLoaderCoordinator>().SingleInstance();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>().SingleInstance();
{
builder.RegisterType<ModuleFolders>().As<IExtensionFolders>()
.WithParameter(new NamedParameter("paths", new[] { "~/Core", "~/Modules" }))
.SingleInstance();
builder.RegisterType<AreaFolders>().As<IExtensionFolders>()
.WithParameter(new NamedParameter("paths", new[] { "~/Areas" }))
.SingleInstance();
builder.RegisterType<ThemeFolders>().As<IExtensionFolders>()
.WithParameter(new NamedParameter("paths", new[] { "~/Core", "~/Themes" }))
.SingleInstance();
builder.RegisterType<ModuleFolders>().As<IExtensionFolders>().SingleInstance()
.WithParameter(new NamedParameter("paths", new[] { "~/Core", "~/Modules" }));
builder.RegisterType<AreaFolders>().As<IExtensionFolders>().SingleInstance()
.WithParameter(new NamedParameter("paths", new[] { "~/Areas" }));
builder.RegisterType<ThemeFolders>().As<IExtensionFolders>().SingleInstance()
.WithParameter(new NamedParameter("paths", new[] { "~/Core", "~/Themes" }));
builder.RegisterType<AreaExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance();
@@ -96,13 +93,6 @@ namespace Orchard.Environment {
builder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
builder.RegisterType<DefaultOrchardShell>().As<IOrchardShell>().InstancePerMatchingLifetimeScope("shell");
// The container provider gives you access to the lowest container at the time,
// and dynamically creates a per-request container. The EndRequestLifetime method
// still needs to be called on end request, but that's the host component's job to worry about
//builder.RegisterType<ContainerProvider>().As<IContainerProvider>().InstancePerLifetimeScope();
registrations(builder);
@@ -114,10 +104,6 @@ namespace Orchard.Environment {
if (File.Exists(optionalHostConfig))
builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig));
builder
.Register(ctx => new LifetimeScopeContainer(ctx.Resolve<ILifetimeScope>()))
.As<IContainer>()
.InstancePerMatchingLifetimeScope("shell");
var container = builder.Build();
@@ -137,6 +123,7 @@ namespace Orchard.Environment {
return container;
}
private static void RegisterVolatileProvider<TRegister, TService>(ContainerBuilder builder) where TService : IVolatileProvider {
builder.RegisterType<TRegister>()
.As<TService>()

View File

@@ -6,7 +6,7 @@ namespace Orchard.Localization {
public class LocalizationUtilities {
public static Localizer Resolve(ControllerContext controllerContext, string scope) {
var context = controllerContext.GetWorkContext();
return context == null ? NullLocalizer.Instance : Resolve(context.Service<ILifetimeScope>(), scope);
return context == null ? NullLocalizer.Instance : Resolve(context.Resolve<ILifetimeScope>(), scope);
}
public static Localizer Resolve(IComponentContext context, string scope) {

View File

@@ -19,7 +19,7 @@ namespace Orchard.Mvc.Html {
if (workContext == null)
throw new ApplicationException("Unable to resolve");
return workContext.Service<TService>();
return workContext.Resolve<TService>();
}
}
}

View File

@@ -1,7 +1,34 @@
using System.Web;
using System;
using System.Web;
namespace Orchard.Mvc {
public interface IHttpContextAccessor {
HttpContextBase Current();
}
public class HttpContextAccessor : IHttpContextAccessor {
public HttpContextBase Current() {
var httpContext = GetStaticProperty();
if (httpContext == null)
return null;
return new HttpContextWrapper(httpContext);
}
private HttpContext GetStaticProperty() {
var httpContext = HttpContext.Current;
if (httpContext == null) {
return null;
}
try {
if (httpContext.Request == null) {
return null;
}
}
catch (Exception) {
return null;
}
return httpContext;
}
}
}

View File

@@ -26,7 +26,7 @@ namespace Orchard.Mvc {
var workContext = workContextAccessor != null ? workContextAccessor.GetContext(requestContext.HttpContext) : null;
if (workContext != null &&
workContext.Service<ILifetimeScope>().TryResolve(service, out controller)) {
workContext.Resolve<ILifetimeScope>().TryResolve(service, out controller)) {
return (IController)controller;
}

View File

@@ -19,7 +19,6 @@ namespace Orchard.Mvc.ViewEngines.Razor {
public abstract class WebViewPage<TModel> : System.Web.Mvc.WebViewPage<TModel> {
private object _display;
private Localizer _localizer = NullLocalizer.Instance;
private IEnumerable<Action> _contexturalizers = Enumerable.Empty<Action>();
public Localizer T { get { return _localizer; } }
@@ -32,7 +31,7 @@ namespace Orchard.Mvc.ViewEngines.Razor {
base.InitHelpers();
var workContext = ViewContext.GetWorkContext();
workContext.Service<IContainer>().InjectUnsetProperties(this);
workContext.Resolve<IComponentContext>().InjectUnsetProperties(this);
_localizer = LocalizationUtilities.Resolve(ViewContext, VirtualPath);
_display = DisplayHelperFactory.CreateHelper(ViewContext, this);

View File

@@ -603,7 +603,6 @@
<Compile Include="Environment\AutofacUtil\DynamicProxy2\ConstructorFinderWrapper.cs" />
<Compile Include="FileSystems\AppData\AppDataFolder.cs" />
<Compile Include="Environment\Configuration\ShellSettingsManager.cs" />
<Compile Include="Environment\AutofacUtil\ContainerUpdater.cs" />
<Compile Include="Environment\ShellBuilders\ShellContextFactory.cs" />
<Compile Include="Environment\ShellBuilders\ShellContext.cs" />
<Compile Include="Environment\Descriptor\ShellDescriptorCache.cs" />

View File

@@ -6,11 +6,11 @@ using Orchard.Logging;
namespace Orchard.Tasks {
public class SweepGenerator : IOrchardShellEvents {
private readonly IContainer _container;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly Timer _timer;
public SweepGenerator(IContainer container) {
_container = container;
public SweepGenerator(IWorkContextAccessor workContextAccessor) {
_workContextAccessor = workContextAccessor;
_timer = new Timer();
_timer.Elapsed += Elapsed;
Logger = NullLogger.Instance;
@@ -56,9 +56,9 @@ namespace Orchard.Tasks {
public void DoWork() {
// makes an inner container, similar to the per-request container
using (var standaloneEnvironment = _container.CreateWorkContextScope()) {
using (var scope = _workContextAccessor.CreateWorkContextScope()) {
// resolve the manager and invoke it
var manager = standaloneEnvironment.Resolve<IBackgroundService>();
var manager = scope.Resolve<IBackgroundService>();
manager.Sweep();
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Web;
using Autofac;
using Orchard.Security;
using Orchard.Settings;
@@ -6,6 +7,9 @@ using Orchard.UI;
namespace Orchard {
public abstract class WorkContext {
public HttpContextBase HttpContext {
get { return State<HttpContextBase>(); }
}
public IPage CurrentPage {
get { return State<IPage>(); }
}
@@ -16,7 +20,7 @@ namespace Orchard {
get { return State<IUser>(); }
}
public abstract T Service<T>();
public abstract T Resolve<T>();
public abstract T State<T>();
}
}