Adding a Setup mode shell container factory

Minimum profile of services needed to function are registered
Certain services are provided by hardcoded replacements implemented only for this context

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-02-04 19:47:24 -08:00
parent 1b273c7a8a
commit 79fe90356b
18 changed files with 367 additions and 117 deletions

View File

@@ -96,7 +96,7 @@ namespace Orchard.Tests.Environment {
[Test]
public void DifferentShellInstanceShouldBeReturnedAfterEachCreate() {
var host = _container.Resolve<IOrchardHost>();
var host = (DefaultOrchardHost)_container.Resolve<IOrchardHost>();
var runtime1 = host.CreateShell();
var runtime2 = host.CreateShell();
Assert.That(runtime1, Is.Not.SameAs(runtime2));

View File

@@ -37,7 +37,6 @@ namespace Orchard.Tests.Environment {
new[] { modelBinderProvider1, modelBinderProvider2 },
modelBinderPublisher,
new ViewEngineCollection { new WebFormViewEngine() },
new Moq.Mock<IExtensionManager>().Object,
Enumerable.Empty<IOrchardShellEvents>());
runtime.Activate();

View File

@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
using NUnit.Framework;
using Orchard.Environment;
using Orchard.Environment.ShellBuilders;
using Orchard.Mvc.Filters;
using Orchard.Mvc.ViewEngines;
namespace Orchard.Tests.Environment.ShellBuilders {
[TestFixture]
public class SetupShellContainerFactoryTests {
private IContainer _hostContainer;
[SetUp]
public void Init() {
_hostContainer = OrchardStarter.CreateHostContainer(builder => {
builder.Register(new ViewEngineCollection());
builder.Register(new RouteCollection());
builder.Register(new ModelBinderDictionary());
});
}
[Test]
public void FactoryShouldCreateContainerThatProvidesShell() {
var factory = new SetupShellContainerFactory(_hostContainer);
var shellContainer = factory.CreateContainer(null);
Assert.That(shellContainer, Is.Not.Null);
var shell = shellContainer.Resolve<IOrchardShell>();
Assert.That(shell, Is.Not.Null);
}
[Test]
public void ShellContainerShouldProvideLayoutViewEngine() {
var factory = new SetupShellContainerFactory(_hostContainer);
var shellContainer = factory.CreateContainer(null);
var viewEngineFilter = shellContainer.Resolve<IEnumerable<IFilterProvider>>()
.Single(f=>f is ViewEngineFilter);
Assert.That(viewEngineFilter, Is.Not.Null);
}
}
}

View File

@@ -141,6 +141,7 @@
<Compile Include="Environment\DefaultOrchardHostTests.cs" />
<Compile Include="Environment\DefaultOrchardShellTests.cs" />
<Compile Include="Environment\OrchardStarterTests.cs" />
<Compile Include="Environment\ShellBuilders\SetupShellContainerFactoryTests.cs" />
<Compile Include="Environment\TestDependencies\TestDependency.cs" />
<Compile Include="EventsTests.cs" />
<Compile Include="Extensions\ExtensionFoldersTests.cs" />

View File

@@ -6,11 +6,8 @@ using Orchard.Logging;
namespace Orchard.Core.Setup.Controllers {
public class SetupController : Controller {
private readonly ISetupService _setupService;
public SetupController(IOrchardServices services, ISetupService setupService) {
_setupService = setupService;
Services = services;
public SetupController() {
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}

View File

@@ -7,6 +7,7 @@ using Autofac.Builder;
using Autofac.Integration.Web;
using System.Collections.Generic;
using AutofacContrib.DynamicProxy2;
using Orchard.Environment.ShellBuilders;
using Orchard.Extensions;
using Orchard.Mvc;
using Orchard.Mvc.ViewEngines;
@@ -14,22 +15,20 @@ using Orchard.Tasks;
namespace Orchard.Environment {
public class DefaultOrchardHost : IOrchardHost {
private readonly IContainer _container;
private readonly IContainerProvider _containerProvider;
private readonly ICompositionStrategy _compositionStrategy;
private readonly ControllerBuilder _controllerBuilder;
private readonly IEnumerable<IShellContainerFactory> _shellContainerFactories;
private IOrchardShell _current;
public DefaultOrchardHost(
IContainerProvider containerProvider,
ICompositionStrategy compositionStrategy,
ControllerBuilder controllerBuilder) {
_container = containerProvider.ApplicationContainer;
ControllerBuilder controllerBuilder,
IEnumerable<IShellContainerFactory> shellContainerFactories) {
_containerProvider = containerProvider;
_compositionStrategy = compositionStrategy;
_controllerBuilder = controllerBuilder;
_shellContainerFactories = shellContainerFactories;
}
@@ -37,6 +36,13 @@ namespace Orchard.Environment {
get { return _current; }
}
void IOrchardHost.Initialize() {
Initialize();
}
void IOrchardHost.EndRequest() {
EndRequest();
}
protected virtual void Initialize() {
var shellContainer = CreateShellContainer();
var shell = shellContainer.Resolve<IOrchardShell>();
@@ -54,6 +60,25 @@ namespace Orchard.Environment {
HackSimulateExtensionActivation(shellContainer);
}
protected virtual void EndRequest() {
_containerProvider.DisposeRequestContainer();
}
public virtual IOrchardShell CreateShell() {
return CreateShellContainer().Resolve<IOrchardShell>();
}
public virtual IContainer CreateShellContainer() {
foreach(var factory in _shellContainerFactories) {
var container = factory.CreateContainer(null);
if (container != null)
return container;
}
return null;
}
private void HackInstallSimulation() {
var tempContainer = CreateShellContainer();
var containerProvider = new FiniteContainerProvider(tempContainer);
@@ -83,98 +108,5 @@ namespace Orchard.Environment {
}
}
protected virtual void EndRequest() {
_containerProvider.DisposeRequestContainer();
}
protected virtual IOrchardShell CreateShell() {
var shellContainer = CreateShellContainer();
return shellContainer.Resolve<IOrchardShell>();
}
public virtual IContainer CreateShellContainer() {
// add module types to container being built
var addingModulesAndServices = new ContainerBuilder();
foreach (var moduleType in _compositionStrategy.GetModuleTypes()) {
addingModulesAndServices.Register(moduleType).As<IModule>().ContainerScoped();
}
// add components by the IDependency interfaces they expose
foreach (var serviceType in _compositionStrategy.GetDependencyTypes()) {
foreach (var interfaceType in serviceType.GetInterfaces()) {
if (typeof(IDependency).IsAssignableFrom(interfaceType)) {
var registrar = addingModulesAndServices.Register(serviceType).As(interfaceType);
if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) {
registrar.SingletonScoped();
}
else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) {
registrar.FactoryScoped();
}
else {
registrar.ContainerScoped();
}
}
}
}
var shellContainer = _container.CreateInnerContainer();
shellContainer.TagWith("shell");
addingModulesAndServices.Build(shellContainer);
// instantiate and register modules on container being built
var modules = shellContainer.Resolve<IEnumerable<IModule>>();
var addingModules = new ContainerBuilder();
foreach (var module in modules) {
addingModules.RegisterModule(module);
}
addingModules.RegisterModule(new ExtensibleInterceptionModule(modules.OfType<IComponentInterceptorProvider>()));
addingModules.Build(shellContainer);
//foreach (var reg in shellContainer.ComponentRegistrations) {
// reg.Preparing += (s, e) => {
// Debug.WriteLine(e.Component.Descriptor.BestKnownImplementationType.FullName);
// };
//}
return shellContainer;
}
#region IOrchardHost Members
void IOrchardHost.Initialize() {
Initialize();
}
void IOrchardHost.EndRequest() {
EndRequest();
}
IOrchardShell IOrchardHost.CreateShell() {
return CreateShell();
}
#endregion
}
public class ExtensibleInterceptionModule : InterceptionModule {
public ExtensibleInterceptionModule(IEnumerable<IComponentInterceptorProvider> providers)
: base(new CombinedProvider(providers.Concat(new[] { new FlexibleInterceptorProvider() })), new FlexibleInterceptorAttacher()) {
}
class CombinedProvider : IComponentInterceptorProvider {
private readonly IEnumerable<IComponentInterceptorProvider> _providers;
public CombinedProvider(IEnumerable<IComponentInterceptorProvider> providers) {
_providers = providers;
}
public IEnumerable<Service> GetInterceptorServices(IComponentDescriptor descriptor) {
return _providers
.SelectMany(x => x.GetInterceptorServices(descriptor))
.Distinct()
.ToList();
}
}
}
}

View File

@@ -15,7 +15,6 @@ namespace Orchard.Environment {
private readonly IEnumerable<IModelBinderProvider> _modelBinderProviders;
private readonly IModelBinderPublisher _modelBinderPublisher;
private readonly ViewEngineCollection _viewEngines;
private readonly IExtensionManager _extensionManager;
private readonly IEnumerable<IOrchardShellEvents> _events;
public DefaultOrchardShell(
@@ -24,14 +23,12 @@ namespace Orchard.Environment {
IEnumerable<IModelBinderProvider> modelBinderProviders,
IModelBinderPublisher modelBinderPublisher,
ViewEngineCollection viewEngines,
IExtensionManager extensionManager,
IEnumerable<IOrchardShellEvents> events) {
_routeProviders = routeProviders;
_routePublisher = routePublisher;
_modelBinderProviders = modelBinderProviders;
_modelBinderPublisher = modelBinderPublisher;
_viewEngines = viewEngines;
_extensionManager = extensionManager;
_events = events;
Logger = NullLogger.Instance;

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Linq;
using Autofac;
using AutofacContrib.DynamicProxy2;
namespace Orchard.Environment {
public class ExtensibleInterceptionModule : InterceptionModule {
public ExtensibleInterceptionModule(IEnumerable<IComponentInterceptorProvider> providers)
: base(new CombinedProvider(providers.Concat(new[] { new FlexibleInterceptorProvider() })), new FlexibleInterceptorAttacher()) {
}
class CombinedProvider : IComponentInterceptorProvider {
private readonly IEnumerable<IComponentInterceptorProvider> _providers;
public CombinedProvider(IEnumerable<IComponentInterceptorProvider> providers) {
_providers = providers;
}
public IEnumerable<Service> GetInterceptorServices(IComponentDescriptor descriptor) {
return _providers
.SelectMany(x => x.GetInterceptorServices(descriptor))
.Distinct()
.ToList();
}
}
}
}

View File

@@ -2,6 +2,5 @@ namespace Orchard.Environment {
public interface IOrchardHost {
void Initialize();
void EndRequest();
IOrchardShell CreateShell();
}
}

View File

@@ -5,6 +5,7 @@ using Autofac.Builder;
using Autofac.Integration.Web;
using Autofac.Modules;
using AutofacContrib.DynamicProxy2;
using Orchard.Environment.ShellBuilders;
using Orchard.Extensions;
using Orchard.Extensions.Loaders;
@@ -17,12 +18,10 @@ namespace Orchard.Environment {
builder.RegisterModule(new ImplicitCollectionSupportModule());
// a single default host implementation is needed for bootstrapping a web app domain
builder.Register<DefaultOrchardHost>().As<IOrchardHost>()
.SingletonScoped();
builder.Register<DefaultCompositionStrategy>().As<ICompositionStrategy>()
.SingletonScoped();
builder.Register<DefaultOrchardShell>().As<IOrchardShell>()
.ContainerScoped().InContext("shell");
builder.Register<DefaultOrchardHost>().As<IOrchardHost>().SingletonScoped();
builder.Register<DefaultCompositionStrategy>().As<ICompositionStrategy>().SingletonScoped();
builder.Register<DefaultShellContainerFactory>().As<IShellContainerFactory>().SingletonScoped();
builder.Register<SetupShellContainerFactory>().As<IShellContainerFactory>().SingletonScoped();
// The container provider gives you access to the lowest container at the time,
// and dynamically creates a per-request container. The DisposeRequestContainer method

View File

@@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Builder;
using AutofacContrib.DynamicProxy2;
namespace Orchard.Environment.ShellBuilders {
public class DefaultShellContainerFactory : IShellContainerFactory {
private readonly IContainer _container;
private readonly ICompositionStrategy _compositionStrategy;
public DefaultShellContainerFactory(IContainer container, ICompositionStrategy compositionStrategy) {
_container = container;
_compositionStrategy = compositionStrategy;
}
public virtual IContainer CreateContainer(IShellSettings settings) {
// null settings means we need to defer to the setup container factory
if (settings == null) {
return null;
}
// add module types to container being built
var addingModulesAndServices = new ContainerBuilder();
addingModulesAndServices.Register<DefaultOrchardShell>().As<IOrchardShell>().SingletonScoped();
foreach (var moduleType in _compositionStrategy.GetModuleTypes()) {
addingModulesAndServices.Register(moduleType).As<IModule>().ContainerScoped();
}
// add components by the IDependency interfaces they expose
foreach (var serviceType in _compositionStrategy.GetDependencyTypes()) {
foreach (var interfaceType in serviceType.GetInterfaces()) {
if (typeof(IDependency).IsAssignableFrom(interfaceType)) {
var registrar = addingModulesAndServices.Register(serviceType).As(interfaceType);
if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) {
registrar.SingletonScoped();
}
else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) {
registrar.FactoryScoped();
}
else {
registrar.ContainerScoped();
}
}
}
}
var shellContainer = _container.CreateInnerContainer();
shellContainer.TagWith("shell");
addingModulesAndServices.Build(shellContainer);
// instantiate and register modules on container being built
var modules = shellContainer.Resolve<IEnumerable<IModule>>();
var addingModules = new ContainerBuilder();
foreach (var module in modules) {
addingModules.RegisterModule(module);
}
addingModules.RegisterModule(new ExtensibleInterceptionModule(modules.OfType<IComponentInterceptorProvider>()));
addingModules.Build(shellContainer);
return shellContainer;
}
}
}

View File

@@ -0,0 +1,7 @@
using Autofac;
namespace Orchard.Environment.ShellBuilders {
public interface IShellContainerFactory {
IContainer CreateContainer(IShellSettings settings);
}
}

View File

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Extensions;
using Orchard.Localization;
using Orchard.Mvc;
using Orchard.Mvc.Filters;
using Orchard.Mvc.ModelBinders;
using Orchard.Mvc.Routes;
using Orchard.Mvc.ViewEngines;
using Orchard.Settings;
using Orchard.Themes;
using Orchard.UI.PageClass;
using Orchard.UI.PageTitle;
using Orchard.UI.Zones;
namespace Orchard.Environment.ShellBuilders {
public class SetupShellContainerFactory : IShellContainerFactory {
private readonly IContainer _container;
public SetupShellContainerFactory(IContainer container) {
_container = container;
}
public IContainer CreateContainer(IShellSettings settings) {
// when you have settings the setup container factory is not in effect
if (settings != null) {
return null;
}
var shellContainer = _container.CreateInnerContainer();
shellContainer.Build(builder => {
builder.Register<DefaultOrchardShell>().As<IOrchardShell>().SingletonScoped();
builder.Register<RoutePublisher>().As<IRoutePublisher>().SingletonScoped();
builder.Register<ModelBinderPublisher>().As<IModelBinderPublisher>().SingletonScoped();
builder.Register(new NullHackInstallationGenerator()).As<IHackInstallationGenerator>().SingletonScoped();
builder.Register(new SetupRouteProvider()).As<IRouteProvider>().SingletonScoped();
builder.Register<MvcModule>().As<IModule>().SingletonScoped();
builder.Register<WebFormsViewEngineProvider>().As<IViewEngineProvider>().ContainerScoped();
builder.Register<ViewEngineFilter>().As<IFilterProvider>().ContainerScoped();
builder.Register<SafeModeThemeService>().As<IThemeService>().SingletonScoped();
builder.Register<SetupText>().As<IText>().SingletonScoped();
builder.Register<PageTitleBuilder>().As<IPageTitleBuilder>().SingletonScoped();
builder.Register<SetupSiteService>().As<ISiteService>().SingletonScoped();
builder.Register<ZoneManager>().As<IZoneManager>().SingletonScoped();
builder.Register<PageClassBuilder>().As<IPageClassBuilder>().SingletonScoped();
});
shellContainer.Build(builder => {
foreach (var module in shellContainer.Resolve<IEnumerable<IModule>>()) {
builder.RegisterModule(module);
}
});
return shellContainer;
}
class SetupRouteProvider : IRouteProvider {
public IEnumerable<RouteDescriptor> GetRoutes() {
var routes = new List<RouteDescriptor>();
GetRoutes(routes);
return routes;
}
public void GetRoutes(ICollection<RouteDescriptor> routes) {
routes.Add(new RouteDescriptor {
Priority = 100,
Route = new Route("{controller}/{action}",
new RouteValueDictionary { { "Area", "Setup" }, { "Controller", "Setup" }, { "Action", "Index" } },
new RouteValueDictionary { { "Area", "Setup" }, { "Controller", "Setup" }, { "Action", "Index" } },
new RouteValueDictionary { { "Area", "Setup" } },
new MvcRouteHandler())
});
}
}
class SetupText : IText {
public LocalizedString Get(string textHint, params object[] args) {
if (args == null || args.Length == 0) {
return new LocalizedString(textHint);
}
return new LocalizedString(string.Format(textHint, args));
}
}
class SafeModeThemeService : IThemeService {
class SafeModeTheme : ITheme {
public ContentItem ContentItem { get; set; }
public string ThemeName { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public string Version { get; set; }
public string Author { get; set; }
public string HomePage { get; set; }
}
private readonly SafeModeTheme _theme = new SafeModeTheme {
ThemeName = "SafeMode",
DisplayName = "SafeMode",
};
public ITheme GetThemeByName(string themeName) { return _theme; }
public ITheme GetSiteTheme() { return _theme; }
public void SetSiteTheme(string themeName) { }
public ITheme GetRequestTheme(RequestContext requestContext) { return _theme; }
public IEnumerable<ITheme> GetInstalledThemes() { return new[] { _theme }; }
public void InstallTheme(HttpPostedFileBase file) { }
public void UninstallTheme(string themeName) { }
}
class NullHackInstallationGenerator : IHackInstallationGenerator {
public void GenerateInstallEvents() { }
public void GenerateActivateEvents() { }
}
class SetupSiteService : ISiteService {
public ISite GetSiteSettings() {
var site = new ContentItemBuilder("site")
.Weld<SetupSite>()
.Build();
return site.As<ISite>();
}
}
class SetupSite : ContentPart, ISite {
public string PageTitleSeparator {
get { return "*"; }
}
public string SiteName {
get { return "Orchard Setup"; }
}
public string SiteSalt {
get { return "42"; }
}
public string SiteUrl {
get { return "/"; }
}
public string SuperUser {
get { return ""; }
}
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Orchard.Environment.ShellBuilders {
public interface IShellSettings {
}
public class ShellSettings : IShellSettings {
}
}

View File

@@ -139,6 +139,10 @@ namespace Orchard.Extensions {
foreach (var descriptor in AvailableExtensions()) {
// Extensions that are Themes don't have buildable components.
if (String.Equals(descriptor.ExtensionType, "Package", StringComparison.OrdinalIgnoreCase)) {
//TEMP!!!!
if (descriptor.DisplayName!="Setup") continue;
yield return BuildEntry(descriptor);
}
}

View File

@@ -24,6 +24,7 @@ namespace Orchard.Mvc.ViewEngines {
_themeService = themeService;
_extensionManager = extensionManager;
_viewEngineProviders = viewEngineProviders;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }

View File

@@ -4,7 +4,9 @@ using Orchard.Logging;
namespace Orchard.Mvc.ViewEngines {
public class WebFormsViewEngineProvider : IViewEngineProvider {
public WebFormsViewEngineProvider() {
Logger = NullLogger.Instance;
}
static string[] DisabledFormats = new[] { "~/Disabled" };
public ILogger Logger { get; set; }
@@ -26,7 +28,7 @@ namespace Orchard.Mvc.ViewEngines {
ViewLocationFormats = DisabledFormats,
AreaMasterLocationFormats = DisabledFormats,
AreaViewLocationFormats = DisabledFormats,
AreaPartialViewLocationFormats=DisabledFormats,
AreaPartialViewLocationFormats = DisabledFormats,
};
// enable /Views/{partialName}

View File

@@ -133,6 +133,11 @@
<Compile Include="ContentManagement\Handlers\RemoveContentContext.cs" />
<Compile Include="ContentManagement\Handlers\VersionContentContext.cs" />
<Compile Include="Data\Conventions\RecordTableNameConvention.cs" />
<Compile Include="Environment\ExtensibleInterceptionModule.cs" />
<Compile Include="Environment\ShellBuilders\DefaultShellContainerFactory.cs" />
<Compile Include="Environment\ShellBuilders\IShellContainerFactory.cs" />
<Compile Include="Environment\ShellBuilders\SetupShellContainerFactory.cs" />
<Compile Include="Environment\ShellBuilders\ShellSettings.cs" />
<Compile Include="Extensions\AreaFolders.cs" />
<Compile Include="Extensions\ExtensionFolders.cs" />
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />