mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Working towards re-enabling setup context
--HG-- branch : dev
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -15,13 +16,29 @@ namespace Orchard.Specs.Bindings {
|
|||||||
public class WebAppHosting {
|
public class WebAppHosting {
|
||||||
private WebHost _webHost;
|
private WebHost _webHost;
|
||||||
private RequestDetails _details;
|
private RequestDetails _details;
|
||||||
|
private MessageSink _messages;
|
||||||
|
|
||||||
[Given(@"I have a clean site")]
|
[Given(@"I have a clean site")]
|
||||||
public void GivenIHaveACleanSite() {
|
public void GivenIHaveACleanSite() {
|
||||||
_webHost = new WebHost();
|
_webHost = new WebHost();
|
||||||
_webHost.Initialize("Orchard.Web", "/");
|
_webHost.Initialize("Orchard.Web", "/");
|
||||||
|
|
||||||
|
var sink = new MessageSink();
|
||||||
|
_webHost.Execute(() => {
|
||||||
|
HostingTraceListener.SetHook(msg => sink.Receive(msg));
|
||||||
|
});
|
||||||
|
_messages = sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class MessageSink : MarshalByRefObject {
|
||||||
|
readonly IList<string> _messages = new List<string>();
|
||||||
|
|
||||||
|
public void Receive(string message) {
|
||||||
|
_messages.Add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Given(@"I have module ""(.*)""")]
|
[Given(@"I have module ""(.*)""")]
|
||||||
public void GivenIHaveModule(string moduleName) {
|
public void GivenIHaveModule(string moduleName) {
|
||||||
_webHost.CopyExtension("Modules", moduleName);
|
_webHost.CopyExtension("Modules", moduleName);
|
||||||
|
|||||||
24
src/Orchard.Specs/Hosting/HostingTraceListener.cs
Normal file
24
src/Orchard.Specs/Hosting/HostingTraceListener.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Orchard.Specs.Hosting {
|
||||||
|
public class HostingTraceListener : TraceListener {
|
||||||
|
private static Action<string> _hook = ignored => { };
|
||||||
|
private string _message;
|
||||||
|
|
||||||
|
public static void SetHook(Action<string> hook) {
|
||||||
|
_hook = hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(string message) {
|
||||||
|
var cumulative = _message + message;
|
||||||
|
_message = cumulative;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteLine(string message) {
|
||||||
|
var cumulative = _message + message;
|
||||||
|
_message = null;
|
||||||
|
_hook(cumulative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<system.diagnostics>
|
||||||
|
<trace autoflush="true"/>
|
||||||
|
<sources>
|
||||||
|
<source name="Default" switchValue="Verbose">
|
||||||
|
<listeners>
|
||||||
|
<add name="CaptureTraceMessages" />
|
||||||
|
</listeners>
|
||||||
|
</source>
|
||||||
|
</sources>
|
||||||
|
<sharedListeners>
|
||||||
|
<add name="CaptureTraceMessages" type="Orchard.Specs.Hosting.HostingTraceListener, Orchard.Specs" initializeData="" />
|
||||||
|
</sharedListeners>
|
||||||
|
</system.diagnostics>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
<appSettings/>
|
<appSettings/>
|
||||||
|
|
||||||
<!--<system.diagnostics configSource="Config\Diagnostics.config" />-->
|
<system.diagnostics configSource="Config\Diagnostics.config" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Set default transaction timeout to 30 minutes so that interactive debugging
|
Set default transaction timeout to 30 minutes so that interactive debugging
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace Orchard.Specs.Hosting {
|
|||||||
VirtualDirectory = virtualDirectory;
|
VirtualDirectory = virtualDirectory;
|
||||||
|
|
||||||
_webHostAgent = (WebHostAgent)ApplicationHost.CreateApplicationHost(typeof(WebHostAgent), VirtualDirectory, PhysicalDirectory);
|
_webHostAgent = (WebHostAgent)ApplicationHost.CreateApplicationHost(typeof(WebHostAgent), VirtualDirectory, PhysicalDirectory);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyExtension(string extensionFolder, string extensionName) {
|
public void CopyExtension(string extensionFolder, string extensionName) {
|
||||||
|
|||||||
@@ -86,6 +86,7 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Hosting\HostingTraceListener.cs" />
|
||||||
<Compile Include="Hosting\Orchard.Web\HelloYetAgainHandler.cs" />
|
<Compile Include="Hosting\Orchard.Web\HelloYetAgainHandler.cs" />
|
||||||
<Compile Include="Hosting\RequestExtensions.cs" />
|
<Compile Include="Hosting\RequestExtensions.cs" />
|
||||||
<Compile Include="Hosting\RequestDetails.cs" />
|
<Compile Include="Hosting\RequestDetails.cs" />
|
||||||
@@ -126,6 +127,9 @@
|
|||||||
<Content Include="Hosting\Orchard.Web\Themes\Web.config">
|
<Content Include="Hosting\Orchard.Web\Themes\Web.config">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<None Include="Hosting\Orchard.Web\Config\Diagnostics.config">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Include="WebHosting.feature">
|
<None Include="WebHosting.feature">
|
||||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>WebHosting.feature.cs</LastGenOutput>
|
<LastGenOutput>WebHosting.feature.cs</LastGenOutput>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Autofac;
|
using Autofac;
|
||||||
using Autofac.Core.Registration;
|
using Autofac.Core.Registration;
|
||||||
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Environment;
|
using Orchard.Environment;
|
||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
@@ -17,16 +18,16 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
|||||||
public void Init() {
|
public void Init() {
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
builder.RegisterType<DefaultShellContextFactory>().As<IShellContextFactory>();
|
builder.RegisterType<DefaultShellContextFactory>().As<IShellContextFactory>();
|
||||||
builder.RegisterAutoMocking();
|
builder.RegisterAutoMocking(Moq.MockBehavior.Strict);
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void NormalExecutionReturnsExpectedObjects() {
|
public void NormalExecutionReturnsExpectedObjects() {
|
||||||
var settings = new ShellSettings {Name = "Default"};
|
var settings = new ShellSettings { Name = "Default" };
|
||||||
var topologyDescriptor = new ShellTopologyDescriptor {SerialNumber = 6655321};
|
var topologyDescriptor = new ShellTopologyDescriptor { SerialNumber = 6655321 };
|
||||||
var topology = new ShellTopology();
|
var topology = new ShellTopology();
|
||||||
ILifetimeScope shellLifetimeScope;
|
var shellLifetimeScope = _container.BeginLifetimeScope("shell");
|
||||||
|
|
||||||
_container.Mock<ITopologyDescriptorCache>()
|
_container.Mock<ITopologyDescriptorCache>()
|
||||||
.Setup(x => x.Fetch("Default"))
|
.Setup(x => x.Fetch("Default"))
|
||||||
@@ -38,7 +39,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
|||||||
|
|
||||||
_container.Mock<IShellContainerFactory>()
|
_container.Mock<IShellContainerFactory>()
|
||||||
.Setup(x => x.CreateContainer(topology))
|
.Setup(x => x.CreateContainer(topology))
|
||||||
.Returns(shellLifetimeScope = _container.BeginLifetimeScope("shell"));
|
.Returns(shellLifetimeScope );
|
||||||
|
|
||||||
_container.Mock<ITopologyDescriptorManager>()
|
_container.Mock<ITopologyDescriptorManager>()
|
||||||
.Setup(x => x.GetTopologyDescriptor())
|
.Setup(x => x.GetTopologyDescriptor())
|
||||||
@@ -54,5 +55,23 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
|||||||
Assert.That(context.LifetimeScope, Is.SameAs(shellLifetimeScope));
|
Assert.That(context.LifetimeScope, Is.SameAs(shellLifetimeScope));
|
||||||
Assert.That(context.Shell, Is.SameAs(shellLifetimeScope.Resolve<IOrchardShell>()));
|
Assert.That(context.Shell, Is.SameAs(shellLifetimeScope.Resolve<IOrchardShell>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void NullSettingsReturnsSetupContext() {
|
||||||
|
var topology = new ShellTopology();
|
||||||
|
|
||||||
|
_container.Mock<ICompositionStrategy>()
|
||||||
|
.Setup(x => x.Compose(It.IsAny<ShellTopologyDescriptor>()))
|
||||||
|
.Returns(topology);
|
||||||
|
|
||||||
|
_container.Mock<IShellContainerFactory>()
|
||||||
|
.Setup(x => x.CreateContainer(topology))
|
||||||
|
.Returns(_container.BeginLifetimeScope("shell"));
|
||||||
|
|
||||||
|
var factory = _container.Resolve<IShellContextFactory>();
|
||||||
|
var context = factory.Create(null);
|
||||||
|
|
||||||
|
Assert.That(context.TopologyDescriptor.EnabledFeatures, Has.Some.With.Property("Name").EqualTo("Setup"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
name: Setup
|
name: Setup
|
||||||
antiforgery: enabled
|
antiforgery: enabled
|
||||||
|
features:
|
||||||
|
Orchard.Setup:
|
||||||
|
description: Components needed to initialize a new instance or tenant
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ namespace Orchard.Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Feature> CoreFeatures() {
|
private static IEnumerable<Feature> CoreFeatures() {
|
||||||
|
var frameworkTypes = typeof(OrchardStarter).Assembly.GetExportedTypes();
|
||||||
|
|
||||||
var core = new Feature {
|
var core = new Feature {
|
||||||
Descriptor = new FeatureDescriptor {
|
Descriptor = new FeatureDescriptor {
|
||||||
Name = "Core",
|
Name = "Core",
|
||||||
@@ -56,11 +58,12 @@ namespace Orchard.Environment {
|
|||||||
AntiForgery = "enabled",
|
AntiForgery = "enabled",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ExportedTypes = new[] {
|
ExportedTypes = frameworkTypes.Where(t => t.IsClass && !t.IsAbstract),
|
||||||
typeof (ContentTypeRecord),
|
//ExportedTypes = new[] {
|
||||||
typeof (ContentItemRecord),
|
// typeof (ContentTypeRecord),
|
||||||
typeof (ContentItemVersionRecord),
|
// typeof (ContentItemRecord),
|
||||||
},
|
// typeof (ContentItemVersionRecord),
|
||||||
|
//},
|
||||||
};
|
};
|
||||||
return new[] { core };
|
return new[] { core };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Environment.ShellBuilders;
|
using Orchard.Environment.ShellBuilders;
|
||||||
|
using Orchard.Logging;
|
||||||
using Orchard.Mvc;
|
using Orchard.Mvc;
|
||||||
using Orchard.Mvc.ViewEngines;
|
using Orchard.Mvc.ViewEngines;
|
||||||
using Orchard.Utility.Extensions;
|
using Orchard.Utility.Extensions;
|
||||||
@@ -29,13 +30,17 @@ namespace Orchard.Environment {
|
|||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_shellContextFactory = shellContextFactory;
|
_shellContextFactory = shellContextFactory;
|
||||||
_controllerBuilder = controllerBuilder;
|
_controllerBuilder = controllerBuilder;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public IList<ShellContext> Current {
|
public IList<ShellContext> Current {
|
||||||
get { return BuildCurrent().ToReadOnlyCollection(); }
|
get { return BuildCurrent().ToReadOnlyCollection(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOrchardHost.Initialize() {
|
void IOrchardHost.Initialize() {
|
||||||
|
Logger.Information("Initializing");
|
||||||
ViewEngines.Engines.Insert(0, LayoutViewEngine.CreateShim());
|
ViewEngines.Engines.Insert(0, LayoutViewEngine.CreateShim());
|
||||||
_controllerBuilder.SetControllerFactory(new OrchardControllerFactory());
|
_controllerBuilder.SetControllerFactory(new OrchardControllerFactory());
|
||||||
ServiceLocator.SetLocator(t => _containerProvider.RequestLifetime.Resolve(t));
|
ServiceLocator.SetLocator(t => _containerProvider.RequestLifetime.Resolve(t));
|
||||||
@@ -57,26 +62,40 @@ namespace Orchard.Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IStandaloneEnvironment IOrchardHost.CreateStandaloneEnvironment(ShellSettings shellSettings) {
|
IStandaloneEnvironment IOrchardHost.CreateStandaloneEnvironment(ShellSettings shellSettings) {
|
||||||
var shellContext = _shellContextFactory.Create(shellSettings);
|
Logger.Debug("Creating standalone environment for tenant {0}", shellSettings.Name);
|
||||||
|
var shellContext = CreateShellContext(shellSettings);
|
||||||
return new StandaloneEnvironment(shellContext.LifetimeScope);
|
return new StandaloneEnvironment(shellContext.LifetimeScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<ShellContext> GetCurrent() {
|
|
||||||
lock (this) {
|
|
||||||
return _current ?? (_current = BuildCurrent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<ShellContext> BuildCurrent() {
|
IEnumerable<ShellContext> BuildCurrent() {
|
||||||
return CreateAndActivate().ToArray();
|
lock (this) {
|
||||||
|
return _current ?? (_current = CreateAndActivate().ToArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<ShellContext> CreateAndActivate() {
|
IEnumerable<ShellContext> CreateAndActivate() {
|
||||||
foreach(var settings in _tenantManager.LoadSettings()) {
|
var allSettings = _tenantManager.LoadSettings();
|
||||||
var context = _shellContextFactory.Create(settings);
|
if (allSettings.Any()) {
|
||||||
context.Shell.Activate();
|
return allSettings.Select(
|
||||||
yield return context;
|
settings => {
|
||||||
|
var context = CreateShellContext(settings);
|
||||||
|
context.Shell.Activate();
|
||||||
|
return context;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new[] {CreateSetupContext()};
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellContext CreateSetupContext() {
|
||||||
|
Logger.Debug("Creating shell context for setup");
|
||||||
|
return _shellContextFactory.Create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShellContext CreateShellContext(ShellSettings settings) {
|
||||||
|
Logger.Debug("Creating shell context for tenant {0}", settings.Name);
|
||||||
|
return _shellContextFactory.Create(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void BeginRequest() {
|
protected virtual void BeginRequest() {
|
||||||
@@ -99,7 +118,7 @@ namespace Orchard.Environment {
|
|||||||
finally {
|
finally {
|
||||||
containerProvider.EndRequestLifetime();
|
containerProvider.EndRequestLifetime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
using System.Web.Mvc;
|
|
||||||
using System.Web.Routing;
|
|
||||||
|
|
||||||
namespace Orchard.Environment {
|
|
||||||
public class HostContext {
|
|
||||||
public ControllerBuilder ControllerBuilder { get; set; }
|
|
||||||
public RouteCollection Routes { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,52 +13,71 @@ using Orchard.Environment.Extensions.Loaders;
|
|||||||
using Orchard.Environment.ShellBuilders;
|
using Orchard.Environment.ShellBuilders;
|
||||||
using Orchard.Environment.Topology;
|
using Orchard.Environment.Topology;
|
||||||
using Orchard.Events;
|
using Orchard.Events;
|
||||||
|
using Orchard.Logging;
|
||||||
|
|
||||||
namespace Orchard.Environment {
|
namespace Orchard.Environment {
|
||||||
public static class OrchardStarter {
|
public static class OrchardStarter {
|
||||||
public static IContainer CreateHostContainer(Action<ContainerBuilder> registrations) {
|
public static IContainer CreateHostContainer(Action<ContainerBuilder> registrations) {
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
|
builder.RegisterModule(new LoggingModule());
|
||||||
|
|
||||||
// a single default host implementation is needed for bootstrapping a web app domain
|
// a single default host implementation is needed for bootstrapping a web app domain
|
||||||
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().SingleInstance();
|
|
||||||
builder.RegisterType<DefaultCompositionStrategy>().As<ICompositionStrategy_Obsolete>().SingleInstance();
|
|
||||||
builder.RegisterType<DefaultShellContainerFactory>().As<IShellContainerFactory>().SingleInstance();
|
|
||||||
builder.RegisterType<AppDataFolder>().As<IAppDataFolder>().SingleInstance();
|
|
||||||
builder.RegisterType<DefaultTenantManager>().As<ITenantManager>().SingleInstance();
|
|
||||||
builder.RegisterType<SafeModeShellContainerFactory>().As<IShellContainerFactory_Obsolete>().SingleInstance();
|
|
||||||
builder.RegisterType<DefaultTopologyDescriptorCache>().As<ITopologyDescriptorCache>().SingleInstance();
|
|
||||||
|
|
||||||
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
||||||
|
builder.RegisterType<AppDataFolder>().As<IAppDataFolder>().SingleInstance();
|
||||||
|
|
||||||
|
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().SingleInstance();
|
||||||
|
{
|
||||||
|
builder.RegisterType<DefaultTenantManager>().As<ITenantManager>().SingleInstance();
|
||||||
|
|
||||||
|
builder.RegisterType<DefaultShellContextFactory>().As<IShellContextFactory>().SingleInstance();
|
||||||
|
{
|
||||||
|
builder.RegisterType<DefaultTopologyDescriptorCache>().As<ITopologyDescriptorCache>().SingleInstance();
|
||||||
|
|
||||||
|
builder.RegisterType<DefaultCompositionStrategy>()
|
||||||
|
.As<ICompositionStrategy>()
|
||||||
|
.As<ICompositionStrategy_Obsolete>()
|
||||||
|
.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<AreaExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||||
|
builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||||
|
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||||
|
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||||
|
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.RegisterType<DefaultShellContainerFactory>().As<IShellContainerFactory>().SingleInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.RegisterType<DefaultOrchardShell>().As<IOrchardShell>().InstancePerMatchingLifetimeScope("shell");
|
||||||
|
|
||||||
// The container provider gives you access to the lowest container at the time,
|
// The container provider gives you access to the lowest container at the time,
|
||||||
// and dynamically creates a per-request container. The EndRequestLifetime method
|
// 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
|
// 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();
|
builder.RegisterType<ContainerProvider>().As<IContainerProvider>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>().SingleInstance();
|
|
||||||
builder.RegisterType<AreaExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
|
||||||
builder.RegisterType<CoreExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
|
||||||
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
|
||||||
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
|
|
||||||
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().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();
|
|
||||||
|
|
||||||
registrations(builder);
|
registrations(builder);
|
||||||
|
|
||||||
|
|
||||||
var autofacSection = ConfigurationManager.GetSection(ConfigurationSettingsReader.DefaultSectionName);
|
var autofacSection = ConfigurationManager.GetSection(ConfigurationSettingsReader.DefaultSectionName);
|
||||||
if (autofacSection != null)
|
if (autofacSection != null)
|
||||||
builder.RegisterModule(new ConfigurationSettingsReader());
|
builder.RegisterModule(new ConfigurationSettingsReader());
|
||||||
|
|
||||||
var optionalHostConfig = HostingEnvironment.MapPath("~/Config/Host.config");
|
var optionalHostConfig = HostingEnvironment.MapPath("~/Config/Host.config");
|
||||||
if (File.Exists(optionalHostConfig))
|
if (File.Exists(optionalHostConfig))
|
||||||
builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig));
|
builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig));
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
|
using Orchard.Environment.Extensions.Models;
|
||||||
using Orchard.Environment.Topology;
|
using Orchard.Environment.Topology;
|
||||||
using Orchard.Environment.Topology.Models;
|
using Orchard.Environment.Topology.Models;
|
||||||
|
using Orchard.Logging;
|
||||||
|
|
||||||
namespace Orchard.Environment.ShellBuilders {
|
namespace Orchard.Environment.ShellBuilders {
|
||||||
public class DefaultShellContextFactory : IShellContextFactory {
|
public class DefaultShellContextFactory : IShellContextFactory {
|
||||||
@@ -16,30 +20,70 @@ namespace Orchard.Environment.ShellBuilders {
|
|||||||
_topologyDescriptorCache = topologyDescriptorCache;
|
_topologyDescriptorCache = topologyDescriptorCache;
|
||||||
_compositionStrategy = compositionStrategy;
|
_compositionStrategy = compositionStrategy;
|
||||||
_shellContainerFactory = shellContainerFactory;
|
_shellContainerFactory = shellContainerFactory;
|
||||||
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public ShellContext Create(ShellSettings settings) {
|
public ShellContext Create(ShellSettings settings) {
|
||||||
var cachedTopology = _topologyDescriptorCache.Fetch(settings.Name);
|
if (settings == null) {
|
||||||
// handle null-(e.g. cache miss)
|
return CreateSetupContext();
|
||||||
|
|
||||||
var topology = _compositionStrategy.Compose(cachedTopology);
|
|
||||||
var shellScope = _shellContainerFactory.CreateContainer(topology);
|
|
||||||
|
|
||||||
ShellTopologyDescriptor currentTopology;
|
|
||||||
using (var standaloneEnvironment = new StandaloneEnvironment(shellScope)) {
|
|
||||||
var topologyDescriptorProvider = standaloneEnvironment.Resolve<ITopologyDescriptorManager>();
|
|
||||||
currentTopology = topologyDescriptorProvider.GetTopologyDescriptor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cachedTopology.SerialNumber != currentTopology.SerialNumber) {
|
Logger.Debug("Creating shell context for tenant {0}", settings.Name);
|
||||||
_topologyDescriptorCache.Store(settings.Name, currentTopology);
|
|
||||||
topology = _compositionStrategy.Compose(currentTopology);
|
var cachedDescriptor = _topologyDescriptorCache.Fetch(settings.Name);
|
||||||
|
if (cachedDescriptor == null) {
|
||||||
|
Logger.Information("No topology cached. Starting with minimum components.");
|
||||||
|
cachedDescriptor = new ShellTopologyDescriptor {
|
||||||
|
SerialNumber = 0,
|
||||||
|
EnabledFeatures = Enumerable.Empty<TopologyFeature>(),
|
||||||
|
Parameters = Enumerable.Empty<TopologyParameter>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// handle null-(e.g. cache miss)
|
||||||
|
|
||||||
|
var topology = _compositionStrategy.Compose(cachedDescriptor);
|
||||||
|
var shellScope = _shellContainerFactory.CreateContainer(topology);
|
||||||
|
|
||||||
|
ShellTopologyDescriptor currentDescriptor;
|
||||||
|
using (var standaloneEnvironment = new StandaloneEnvironment(shellScope)) {
|
||||||
|
var topologyDescriptorProvider = standaloneEnvironment.Resolve<ITopologyDescriptorManager>();
|
||||||
|
currentDescriptor = topologyDescriptorProvider.GetTopologyDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cachedDescriptor.SerialNumber != currentDescriptor.SerialNumber) {
|
||||||
|
Logger.Information("Newer topology obtained. Rebuilding shell container.");
|
||||||
|
|
||||||
|
_topologyDescriptorCache.Store(settings.Name, currentDescriptor);
|
||||||
|
topology = _compositionStrategy.Compose(currentDescriptor);
|
||||||
shellScope = _shellContainerFactory.CreateContainer(topology);
|
shellScope = _shellContainerFactory.CreateContainer(topology);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ShellContext {
|
return new ShellContext {
|
||||||
Settings = settings,
|
Settings = settings,
|
||||||
TopologyDescriptor = currentTopology,
|
TopologyDescriptor = currentDescriptor,
|
||||||
|
Topology = topology,
|
||||||
|
LifetimeScope = shellScope,
|
||||||
|
Shell = shellScope.Resolve<IOrchardShell>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShellContext CreateSetupContext() {
|
||||||
|
Logger.Warning("No shell settings available. Creating shell context for setup");
|
||||||
|
|
||||||
|
var settings = new ShellSettings { Name = "__Orchard__Setup__" };
|
||||||
|
var descriptor = new ShellTopologyDescriptor {
|
||||||
|
SerialNumber = -1,
|
||||||
|
EnabledFeatures = new[] { new TopologyFeature { Name = "Orchard.Setup" } },
|
||||||
|
};
|
||||||
|
|
||||||
|
var topology = _compositionStrategy.Compose(descriptor);
|
||||||
|
var shellScope = _shellContainerFactory.CreateContainer(topology);
|
||||||
|
|
||||||
|
return new ShellContext {
|
||||||
|
Settings = settings,
|
||||||
|
TopologyDescriptor = descriptor,
|
||||||
Topology = topology,
|
Topology = topology,
|
||||||
LifetimeScope = shellScope,
|
LifetimeScope = shellScope,
|
||||||
Shell = shellScope.Resolve<IOrchardShell>(),
|
Shell = shellScope.Resolve<IOrchardShell>(),
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Orchard.Environment.Topology.Models {
|
namespace Orchard.Environment.Topology.Models {
|
||||||
public class ShellTopologyDescriptor {
|
public class ShellTopologyDescriptor {
|
||||||
|
public ShellTopologyDescriptor() {
|
||||||
|
EnabledFeatures = Enumerable.Empty<TopologyFeature>();
|
||||||
|
Parameters = Enumerable.Empty<TopologyParameter>();
|
||||||
|
}
|
||||||
|
|
||||||
public int SerialNumber { get; set; }
|
public int SerialNumber { get; set; }
|
||||||
public IEnumerable<TopologyFeature> EnabledFeatures { get; set; }
|
public IEnumerable<TopologyFeature> EnabledFeatures { get; set; }
|
||||||
public IEnumerable<TopologyParameter> Parameters { get; set; }
|
public IEnumerable<TopologyParameter> Parameters { get; set; }
|
||||||
|
|||||||
@@ -126,7 +126,6 @@
|
|||||||
<Compile Include="Environment\DefaultCompositionStrategy.cs" />
|
<Compile Include="Environment\DefaultCompositionStrategy.cs" />
|
||||||
<Compile Include="Environment\DefaultOrchardHost.cs" />
|
<Compile Include="Environment\DefaultOrchardHost.cs" />
|
||||||
<Compile Include="Mvc\OrchardControllerFactory.cs" />
|
<Compile Include="Mvc\OrchardControllerFactory.cs" />
|
||||||
<Compile Include="Environment\HostContext.cs" />
|
|
||||||
<Compile Include="Environment\IOrchardHost.cs" />
|
<Compile Include="Environment\IOrchardHost.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Validation\Argument.cs" />
|
<Compile Include="Validation\Argument.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user