Adding the ability to create an isolated environment from a given shell settings

This is needed for the setup scenario, where the entire set of components with appropriate settings will need to be
available to initialize the system

--HG--
branch : dev
This commit is contained in:
Louis DeJardin 2010-02-05 18:03:58 -08:00
parent 673fd674fd
commit 43381c5a6d
8 changed files with 87 additions and 27 deletions

View File

@ -1,4 +1,8 @@
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.Data.Migrations;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Setup.ViewModels; using Orchard.Setup.ViewModels;
using Orchard.Localization; using Orchard.Localization;
using Orchard.UI.Notify; using Orchard.UI.Notify;
@ -6,9 +10,16 @@ using Orchard.UI.Notify;
namespace Orchard.Setup.Controllers { namespace Orchard.Setup.Controllers {
public class SetupController : Controller { public class SetupController : Controller {
private readonly INotifier _notifier; private readonly INotifier _notifier;
private readonly IDatabaseMigrationManager _databaseMigrationManager;
private readonly IOrchardHost _orchardHost;
public SetupController(INotifier notifier) { public SetupController(
INotifier notifier,
IDatabaseMigrationManager databaseMigrationManager,
IOrchardHost orchardHost) {
_notifier = notifier; _notifier = notifier;
_databaseMigrationManager = databaseMigrationManager;
_orchardHost = orchardHost;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
@ -25,11 +36,28 @@ namespace Orchard.Setup.Controllers {
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
return View(model); return View(model);
} }
//notes: service call to initialize database:
//_databaseMigrationManager.CreateCoordinator(provider, dataFolder, connectionString);
// provider: SqlServer or SQLite
// dataFolder: physical path (map before calling). Builtin database will be created in this location
// connectionString: optional - if provided the dataFolder is essentially ignored, but should still be passed in
// create superuser //notes: the other tool needed will be creating a standalone environment.
// set site name // in theory this environment can be used to resolve any normal components by interface, and those
// database // components will exist entirely in isolation - no crossover between the safemode container currently in effect
// redirect to the welcome page var shellSettings = new ShellSettings { Name = "temp" };
using (var finiteEnvironment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
var contentManager = finiteEnvironment.Resolve<IContentManager>();
var yadda = contentManager.Create("yadda");
// create superuser
// set site name
// database
// redirect to the welcome page
}
_notifier.Information(T("Setup succeeded")); _notifier.Information(T("Setup succeeded"));
return RedirectToAction("Index"); return RedirectToAction("Index");

View File

@ -38,10 +38,16 @@ namespace Orchard.Environment {
void IOrchardHost.Initialize() { void IOrchardHost.Initialize() {
Initialize(); Initialize();
} }
void IOrchardHost.EndRequest() { void IOrchardHost.EndRequest() {
EndRequest(); EndRequest();
} }
IStandaloneEnvironment IOrchardHost.CreateStandaloneEnvironment(IShellSettings shellSettings) {
var shellContainer = CreateShellContainer(shellSettings);
return new StandaloneEnvironment(shellContainer);
}
protected virtual void Initialize() { protected virtual void Initialize() {
var shellContainer = CreateShellContainer(); var shellContainer = CreateShellContainer();
var shell = shellContainer.Resolve<IOrchardShell>(); var shell = shellContainer.Resolve<IOrchardShell>();
@ -73,18 +79,18 @@ namespace Orchard.Environment {
var settings = _shellSettingsLoader.LoadSettings(); var settings = _shellSettingsLoader.LoadSettings();
if (settings.Any()) { if (settings.Any()) {
//TEMP: multi-tenancy not implemented yet //TEMP: multi-tenancy not implemented yet
foreach (var factory in _shellContainerFactories) { var shellContainer = CreateShellContainer(settings.Single());
var container = factory.CreateContainer(settings.Single()); if (shellContainer != null)
if (container != null) return shellContainer;
return container;
}
} }
else { return CreateShellContainer(null);
foreach (var factory in _shellContainerFactories) { }
var container = factory.CreateContainer(null);
if (container != null) private IContainer CreateShellContainer(IShellSettings shellSettings) {
return container; foreach (var factory in _shellContainerFactories) {
} var container = factory.CreateContainer(shellSettings);
if (container != null)
return container;
} }
return null; return null;
} }
@ -118,5 +124,6 @@ namespace Orchard.Environment {
} }
} }
} }
} }

View File

@ -2,6 +2,7 @@ using Autofac;
using Autofac.Integration.Web; using Autofac.Integration.Web;
namespace Orchard.Environment { namespace Orchard.Environment {
class FiniteContainerProvider : IContainerProvider { class FiniteContainerProvider : IContainerProvider {
public FiniteContainerProvider(IContainer applicationContainer) { public FiniteContainerProvider(IContainer applicationContainer) {
// explicitly create a request container for the life of this object // explicitly create a request container for the life of this object

View File

@ -1,6 +1,10 @@
using Orchard.Environment.Configuration;
namespace Orchard.Environment { namespace Orchard.Environment {
public interface IOrchardHost { public interface IOrchardHost {
void Initialize(); void Initialize();
void EndRequest(); void EndRequest();
IStandaloneEnvironment CreateStandaloneEnvironment(IShellSettings shellSettings);
} }
} }

View File

@ -5,6 +5,7 @@ using System.Web.Routing;
using Autofac; using Autofac;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Data.Migrations;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Extensions; using Orchard.Extensions;
using Orchard.Localization; using Orchard.Localization;
@ -37,7 +38,6 @@ namespace Orchard.Environment.ShellBuilders {
var shellContainer = _container.CreateInnerContainer(); var shellContainer = _container.CreateInnerContainer();
shellContainer.Build(builder => { shellContainer.Build(builder => {
//review: group by default vs safemode service replacements
// standard services needed in safe mode // standard services needed in safe mode
builder.Register<DefaultOrchardShell>().As<IOrchardShell>().ContainerScoped(); builder.Register<DefaultOrchardShell>().As<IOrchardShell>().ContainerScoped();
builder.Register<RoutePublisher>().As<IRoutePublisher>().ContainerScoped(); builder.Register<RoutePublisher>().As<IRoutePublisher>().ContainerScoped();
@ -50,6 +50,7 @@ namespace Orchard.Environment.ShellBuilders {
builder.Register<PageClassBuilder>().As<IPageClassBuilder>().ContainerScoped(); builder.Register<PageClassBuilder>().As<IPageClassBuilder>().ContainerScoped();
builder.Register<Notifier>().As<INotifier>().ContainerScoped(); builder.Register<Notifier>().As<INotifier>().ContainerScoped();
builder.Register<NotifyFilter>().As<IFilterProvider>().ContainerScoped(); builder.Register<NotifyFilter>().As<IFilterProvider>().ContainerScoped();
builder.Register<DatabaseMigrationManager>().As<IDatabaseMigrationManager>().ContainerScoped();
// safe mode specific implementations of needed service interfaces // safe mode specific implementations of needed service interfaces
builder.Register<NullHackInstallationGenerator>().As<IHackInstallationGenerator>().ContainerScoped(); builder.Register<NullHackInstallationGenerator>().As<IHackInstallationGenerator>().ContainerScoped();

View File

@ -0,0 +1,25 @@
using System;
using Autofac;
using Autofac.Integration.Web;
namespace Orchard.Environment {
public interface IStandaloneEnvironment : IDisposable {
TService Resolve<TService>();
}
public class StandaloneEnvironment : IStandaloneEnvironment {
private readonly IContainerProvider _containerProvider;
public StandaloneEnvironment(IContainer applicationContainer) {
_containerProvider = new FiniteContainerProvider(applicationContainer);
}
public TService Resolve<TService>() {
return _containerProvider.RequestContainer.Resolve<TService>();
}
public void Dispose() {
_containerProvider.DisposeRequestContainer();
}
}
}

View File

@ -145,6 +145,7 @@
<Compile Include="Environment\ShellBuilders\IShellContainerFactory.cs" /> <Compile Include="Environment\ShellBuilders\IShellContainerFactory.cs" />
<Compile Include="Environment\ShellBuilders\SafeModeShellContainerFactory.cs" /> <Compile Include="Environment\ShellBuilders\SafeModeShellContainerFactory.cs" />
<Compile Include="Environment\Configuration\ShellSettings.cs" /> <Compile Include="Environment\Configuration\ShellSettings.cs" />
<Compile Include="Environment\StandaloneEnvironment.cs" />
<Compile Include="Extensions\AreaFolders.cs" /> <Compile Include="Extensions\AreaFolders.cs" />
<Compile Include="Extensions\ExtensionFolders.cs" /> <Compile Include="Extensions\ExtensionFolders.cs" />
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" /> <Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />

View File

@ -56,18 +56,11 @@ namespace Orchard.Tasks {
public void DoWork() { public void DoWork() {
// makes an inner container, similar to the per-request container // makes an inner container, similar to the per-request container
var containerProvider = new FiniteContainerProvider(_container); using (var standaloneEnvironment = new StandaloneEnvironment(_container)) {
try {
var requestContainer = containerProvider.RequestContainer;
// resolve the manager and invoke it // resolve the manager and invoke it
var manager = requestContainer.Resolve<IBackgroundService>(); var manager = standaloneEnvironment.Resolve<IBackgroundService>();
manager.Sweep(); manager.Sweep();
} }
finally{
// shut everything down again
containerProvider.DisposeRequestContainer();
}
} }
} }