Working towards re-enabling setup context

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-04-17 19:22:26 -07:00
parent 1cfaae90b8
commit a137d84732
15 changed files with 235 additions and 73 deletions

View File

@@ -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);

View 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);
}
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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"));
}
} }
} }

View File

@@ -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

View File

@@ -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 };
} }

View File

@@ -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();
} }
} }
} }
} }

View File

@@ -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; }
}
}

View File

@@ -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));

View File

@@ -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>(),

View File

@@ -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; }

View File

@@ -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" />