From d9598d020f863d2ad13e3733ebefe68bd4fde6e5 Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Wed, 14 Apr 2010 18:22:23 -0700 Subject: [PATCH] Adding a specific component to orchetrate the creation of a shell context --HG-- branch : dev --- .../Hosting/RequestExtensions.cs | 8 +- .../DefaultShellContextFactoryTests.cs | 98 +++++++++++++++++++ .../Orchard.Framework.Tests.csproj | 1 + src/Orchard/Environment/DefaultOrchardHost.cs | 11 ++- .../DefaultShellContextFactory.cs | 50 ++++++++++ .../ShellBuilders/IShellContextFactory.cs | 7 ++ .../Environment/ShellBuilders/ShellContext.cs | 13 +++ src/Orchard/Orchard.Framework.csproj | 3 + 8 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs create mode 100644 src/Orchard/Environment/ShellBuilders/DefaultShellContextFactory.cs create mode 100644 src/Orchard/Environment/ShellBuilders/IShellContextFactory.cs create mode 100644 src/Orchard/Environment/ShellBuilders/ShellContext.cs diff --git a/src/Orchard.Specs/Hosting/RequestExtensions.cs b/src/Orchard.Specs/Hosting/RequestExtensions.cs index 9e99e36e6..b53ec1dc7 100644 --- a/src/Orchard.Specs/Hosting/RequestExtensions.cs +++ b/src/Orchard.Specs/Hosting/RequestExtensions.cs @@ -25,8 +25,7 @@ namespace Orchard.Specs.Hosting webHost.Execute(() => { var output = new StringWriter(); - var worker = new Worker(details, output); - HttpRuntime.ProcessRequest(worker); + HttpRuntime.ProcessRequest(new Worker(details, output)); details.ResponseText = output.ToString(); }); @@ -35,8 +34,8 @@ namespace Orchard.Specs.Hosting class Worker : SimpleWorkerRequest { - private RequestDetails _details; - private TextWriter _output; + private readonly RequestDetails _details; + private readonly TextWriter _output; public Worker(RequestDetails details, TextWriter output) : base(details.Page, details.Query, output) @@ -60,3 +59,4 @@ namespace Orchard.Specs.Hosting } } } + diff --git a/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs b/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs new file mode 100644 index 000000000..886b5590b --- /dev/null +++ b/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Autofac; +using Autofac.Builder; +using Autofac.Core; +using Autofac.Core.Registration; +using Moq; +using NUnit.Framework; +using Orchard.Environment; +using Orchard.Environment.Configuration; +using Orchard.Environment.ShellBuilders; +using Orchard.Environment.Topology; +using Orchard.Environment.Topology.Models; + +namespace Orchard.Tests.Environment.ShellBuilders { + [TestFixture] + public class DefaultShellContextFactoryTests { + private IContainer _container; + + [SetUp] + public void Init() { + var builder = new ContainerBuilder(); + builder.RegisterType().As(); + builder.RegisterSource(new MockServiceSource()); + _container = builder.Build(); + } + + [Test] + public void NormalExecutionReturnsExpectedObjects() { + var settings = new ShellSettings {Name = "Default"}; + var topologyDescriptor = new ShellTopologyDescriptor {SerialNumber = 6655321}; + var topology = new ShellTopology(); + ILifetimeScope shellLifetimeScope; + + _container.Mock() + .Setup(x => x.Fetch("Default")) + .Returns(topologyDescriptor); + + _container.Mock() + .Setup(x => x.Compose(topologyDescriptor)) + .Returns(topology); + + _container.Mock() + .Setup(x => x.CreateContainer(topology)) + .Returns(shellLifetimeScope = _container.BeginLifetimeScope("shell")); + + _container.Mock() + .Setup(x => x.GetTopologyDescriptor()) + .Returns(topologyDescriptor); + + var factory = _container.Resolve(); + + var context = factory.Create(settings); + + Assert.That(context.Settings, Is.SameAs(settings)); + Assert.That(context.TopologyDescriptor, Is.SameAs(topologyDescriptor)); + Assert.That(context.Topology, Is.SameAs(topology)); + Assert.That(context.LifetimeScope, Is.SameAs(shellLifetimeScope)); + Assert.That(context.Shell, Is.SameAs(shellLifetimeScope.Resolve())); + } + } + + class MockServiceSource : IRegistrationSource { + public IEnumerable RegistrationsFor( + Service service, + Func> registrationAccessor) { + + var swt = service as IServiceWithType; + if (swt == null) + yield break; + var st = swt.ServiceType; + + if (st.IsGenericType && st.GetGenericTypeDefinition() == typeof(Mock<>)) { + yield return RegistrationBuilder.ForType(st).SingleInstance().CreateRegistration(); + } + else if (st.IsInterface) { + yield return RegistrationBuilder.ForDelegate( + (ctx, p) => { + Trace.WriteLine(string.Format("Mocking {0}", st)); + var mt = typeof(Mock<>).MakeGenericType(st); + var m = (Mock)ctx.Resolve(mt); + return m.Object; + }) + .As(service) + .SingleInstance() + .CreateRegistration(); + + } + } + } + + public static class MockExtensions { + public static Mock Mock(this IContainer container) where T : class { + return container.Resolve>(); + } + } +} diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index 5ba15ca2e..0a4657ccc 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -163,6 +163,7 @@ + diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 33b0955c9..659f32017 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Web.Mvc; using Autofac; @@ -5,6 +6,8 @@ using Autofac.Integration.Web; using System.Collections.Generic; using Orchard.Environment.Configuration; using Orchard.Environment.ShellBuilders; +using Orchard.Environment.Topology; +using Orchard.Environment.Topology.Models; using Orchard.Extensions; using Orchard.Mvc; using Orchard.Mvc.ViewEngines; @@ -22,6 +25,9 @@ namespace Orchard.Environment { public DefaultOrchardHost( IContainerProvider containerProvider, ITenantManager tenantManager, + ITopologyDescriptorCache topologyDescriptorCache, + ICompositionStrategy compositionStrategy, + IShellContainerFactory shellContainerFactory, ControllerBuilder controllerBuilder, IEnumerable shellContainerFactories) { _containerProvider = containerProvider; @@ -126,6 +132,7 @@ namespace Orchard.Environment { finally { containerProvider.EndRequestLifetime(); } - } + } + } -} \ No newline at end of file +} diff --git a/src/Orchard/Environment/ShellBuilders/DefaultShellContextFactory.cs b/src/Orchard/Environment/ShellBuilders/DefaultShellContextFactory.cs new file mode 100644 index 000000000..e19d3e70b --- /dev/null +++ b/src/Orchard/Environment/ShellBuilders/DefaultShellContextFactory.cs @@ -0,0 +1,50 @@ +using Autofac; +using Orchard.Environment.Configuration; +using Orchard.Environment.Topology; +using Orchard.Environment.Topology.Models; + +namespace Orchard.Environment.ShellBuilders { + public class DefaultShellContextFactory : IShellContextFactory { + private readonly ITopologyDescriptorCache _topologyDescriptorCache; + private readonly ICompositionStrategy _compositionStrategy; + private readonly IShellContainerFactory _shellContainerFactory; + + public DefaultShellContextFactory( + ITopologyDescriptorCache topologyDescriptorCache, + ICompositionStrategy compositionStrategy, + IShellContainerFactory shellContainerFactory) { + _topologyDescriptorCache = topologyDescriptorCache; + _compositionStrategy = compositionStrategy; + _shellContainerFactory = shellContainerFactory; + } + + public ShellContext Create(ShellSettings settings) { + var cachedTopology = _topologyDescriptorCache.Fetch(settings.Name); + // handle null-(e.g. cache miss) + + var topology = _compositionStrategy.Compose(cachedTopology); + var shellScope = _shellContainerFactory.CreateContainer(topology); + + ShellTopologyDescriptor currentTopology; + using (var standaloneEnvironment = new StandaloneEnvironment(shellScope)) { + var topologyDescriptorProvider = standaloneEnvironment.Resolve(); + currentTopology = topologyDescriptorProvider.GetTopologyDescriptor(); + } + + if (cachedTopology.SerialNumber != currentTopology.SerialNumber) { + _topologyDescriptorCache.Store(settings.Name, currentTopology); + topology = _compositionStrategy.Compose(currentTopology); + shellScope = _shellContainerFactory.CreateContainer(topology); + } + + var shell = shellScope.Resolve(); + return new ShellContext { + Settings = settings, + TopologyDescriptor = currentTopology, + Topology = topology, + LifetimeScope = shellScope, + Shell = shellScope.Resolve(), + }; + } + } +} \ No newline at end of file diff --git a/src/Orchard/Environment/ShellBuilders/IShellContextFactory.cs b/src/Orchard/Environment/ShellBuilders/IShellContextFactory.cs new file mode 100644 index 000000000..707a7e4f4 --- /dev/null +++ b/src/Orchard/Environment/ShellBuilders/IShellContextFactory.cs @@ -0,0 +1,7 @@ +using Orchard.Environment.Configuration; + +namespace Orchard.Environment.ShellBuilders { + public interface IShellContextFactory { + ShellContext Create(ShellSettings settings); + } +} diff --git a/src/Orchard/Environment/ShellBuilders/ShellContext.cs b/src/Orchard/Environment/ShellBuilders/ShellContext.cs new file mode 100644 index 000000000..0fc5cf008 --- /dev/null +++ b/src/Orchard/Environment/ShellBuilders/ShellContext.cs @@ -0,0 +1,13 @@ +using Autofac; +using Orchard.Environment.Configuration; +using Orchard.Environment.Topology.Models; + +namespace Orchard.Environment.ShellBuilders { + public class ShellContext { + public ShellSettings Settings { get; set; } + public ShellTopologyDescriptor TopologyDescriptor { get; set; } + public ShellTopology Topology { get; set; } + public ILifetimeScope LifetimeScope { get; set; } + public IOrchardShell Shell { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 6a220f802..b6de60ab6 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -167,6 +167,9 @@ + + +