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 Orchard.ContentManagement;
using Orchard.Data.Migrations;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Setup.ViewModels;
using Orchard.Localization;
using Orchard.UI.Notify;
@ -6,9 +10,16 @@ using Orchard.UI.Notify;
namespace Orchard.Setup.Controllers {
public class SetupController : Controller {
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;
_databaseMigrationManager = databaseMigrationManager;
_orchardHost = orchardHost;
T = NullLocalizer.Instance;
}
@ -25,11 +36,28 @@ namespace Orchard.Setup.Controllers {
if (!ModelState.IsValid) {
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
// set site name
// database
// redirect to the welcome page
//notes: the other tool needed will be creating a standalone environment.
// in theory this environment can be used to resolve any normal components by interface, and those
// components will exist entirely in isolation - no crossover between the safemode container currently in effect
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"));
return RedirectToAction("Index");

View File

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

View File

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

View File

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

View File

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

View File

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