mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-24 05:23:33 +08:00
Further progress towards tenant-specific routing
Ability to follow redirects from integration tests Route publisher wraps handler with ShellRoute which controls request lifetime scope ShellRoute at the moment is restricted to "Default" - host and prefix TBD Route publisher remove-and-insert routes for a specific tenant to allow incremental and repeated shell route publish Offers a more deterministic knowledge of which shell container is used than just-in-time http context Removes Autofac default httpmodule, controller factory, httpapplication icontainerprovideraccessor, etc Adds support for optional ~/Config/Sites.{yourtenantname}.config file for manual per-shell component override Integration tests capture Orchard and NHibernate trace output. Levels are configurable in orchard.specs diagnostics.config Concept of IRunningShellTable instroduced. Might not be needed - will be removed if so. --HG-- branch : dev
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Topology;
|
||||
@@ -46,6 +47,8 @@ namespace Orchard.Specs.Bindings {
|
||||
descriptor.EnabledFeatures.Concat(new[] { new ShellFeature { Name = name } }),
|
||||
descriptor.Parameters);
|
||||
}
|
||||
|
||||
Trace.WriteLine("This call to Host.Reinitialize should not be needed, eventually");
|
||||
MvcApplication.Host.Reinitialize_Obsolete();
|
||||
});
|
||||
|
||||
|
@@ -1,12 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using System.Xml.Linq;
|
||||
using Castle.Core.Logging;
|
||||
using HtmlAgilityPack;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Repository;
|
||||
using Orchard.Specs.Hosting;
|
||||
using Orchard.Specs.Util;
|
||||
using TechTalk.SpecFlow;
|
||||
@@ -34,12 +40,51 @@ namespace Orchard.Specs.Bindings {
|
||||
public void GivenIHaveACleanSiteBasedOn(string siteFolder) {
|
||||
_webHost = new WebHost();
|
||||
Host.Initialize(siteFolder, "/");
|
||||
|
||||
var sink = new MessageSink();
|
||||
var cb = new cb1();
|
||||
Host.Execute(() => {
|
||||
HostingTraceListener.SetHook(msg => sink.Receive(msg));
|
||||
log4net.Config.BasicConfigurator.Configure(new CallAppender(cb.cb2));
|
||||
HostingTraceListener.SetHook(msg => cb.sink.Receive(" "+ msg));
|
||||
});
|
||||
_messages = sink;
|
||||
_messages = cb.sink;
|
||||
}
|
||||
|
||||
public class CallAppender : IAppender {
|
||||
private readonly cb2 _cb2;
|
||||
public CallAppender(cb2 cb2) { _cb2 = cb2; }
|
||||
public void Close() { }
|
||||
public string Name { get; set; }
|
||||
|
||||
public void DoAppend(LoggingEvent loggingEvent) {
|
||||
var traceLoggerFactory = new TraceLoggerFactory();
|
||||
var logger = traceLoggerFactory.Create(loggingEvent.LoggerName);
|
||||
if (loggingEvent.Level <= Level.Debug)
|
||||
logger.Debug(loggingEvent.RenderedMessage);
|
||||
else if (loggingEvent.Level <= Level.Info)
|
||||
logger.Info(loggingEvent.RenderedMessage);
|
||||
else if (loggingEvent.Level <= Level.Warn)
|
||||
logger.Warn(loggingEvent.RenderedMessage);
|
||||
else if (loggingEvent.Level <= Level.Error)
|
||||
logger.Error(loggingEvent.RenderedMessage);
|
||||
else
|
||||
logger.Fatal(loggingEvent.RenderedMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class cb1 {
|
||||
public cb2 cb2 = new cb2();
|
||||
public MessageSink sink = new MessageSink();
|
||||
|
||||
}
|
||||
|
||||
public class cb2 : MarshalByRefObject {
|
||||
private IDictionary<string, TraceSource> _sources;
|
||||
public void Trace(string loggerName, Level level, string message) {
|
||||
var traceLoggerFactory = new TraceLoggerFactory();
|
||||
traceLoggerFactory.Create(loggerName).Info(message);
|
||||
//System.Diagnostics.Trace.WriteLine(message);
|
||||
}
|
||||
}
|
||||
|
||||
[Given(@"I have module ""(.*)""")]
|
||||
@@ -135,6 +180,16 @@ namespace Orchard.Specs.Bindings {
|
||||
_doc.Load(new StringReader(_details.ResponseText));
|
||||
}
|
||||
|
||||
[When(@"I am redirected")]
|
||||
public void WhenIAmRedirected() {
|
||||
var urlPath = "";
|
||||
if (_details.ResponseHeaders.TryGetValue("Location", out urlPath)) {
|
||||
WhenIGoTo(urlPath);
|
||||
}
|
||||
else {
|
||||
Assert.Fail("No Location header returned");
|
||||
}
|
||||
}
|
||||
|
||||
[Then(@"the status should be (.*) (.*)")]
|
||||
public void ThenTheStatusShouldBe(int statusCode, string statusDescription) {
|
||||
|
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Orchard.Specs.Hosting {
|
||||
public class MessageSink : MarshalByRefObject {
|
||||
readonly IList<string> _messages = new List<string>();
|
||||
|
||||
public void Receive(string message) {
|
||||
Trace.WriteLine(message);
|
||||
_messages.Add(message);
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,36 @@
|
||||
<system.diagnostics>
|
||||
<trace autoflush="true"/>
|
||||
<sources>
|
||||
<source name="Default" switchValue="Verbose">
|
||||
<source name="Default" switchValue="Warning">
|
||||
<listeners>
|
||||
<add name="CaptureTraceMessages" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="Orchard" switchValue="Verbose">
|
||||
<listeners>
|
||||
<add name="CaptureTraceMessages" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="Orchard.Data.SessionLocator" switchValue="Information">
|
||||
<listeners>
|
||||
<add name="CaptureTraceMessages" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="NHibernate.SQL" switchValue="Verbose">
|
||||
<listeners>
|
||||
<add name="CaptureTraceMessages" />
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="Orchard.Mvc.ViewEngines.WebFormsViewEngineProvider" switchValue="Warning">
|
||||
<listeners>
|
||||
<add name="CaptureTraceMessages" />
|
||||
</listeners>
|
||||
</source>
|
||||
<!--<source name="Orchard.Localization.Text" switchValue="Warning"/>
|
||||
<source name="Orchard.Mvc.ViewEngines.WebFormsViewEngineProvider" switchValue="Warning"/>-->
|
||||
|
||||
</sources>
|
||||
<sharedListeners>
|
||||
<add name="CaptureTraceMessages" type="Orchard.Specs.Hosting.HostingTraceListener, Orchard.Specs" initializeData="" />
|
||||
<add name="CaptureTraceMessages" type="Orchard.Specs.Hosting.HostingTraceListener, Orchard.Specs" initializeData="" />
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
|
25
src/Orchard.Specs/Hosting/Orchard.Web/Config/Host.config
Normal file
25
src/Orchard.Specs/Hosting/Orchard.Web/Config/Host.config
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
|
||||
</configSections>
|
||||
|
||||
<autofac defaultAssembly="Orchard.Framework">
|
||||
<components>
|
||||
|
||||
<!--<component instance-scope="single-instance"
|
||||
type="Orchard.Environment.Configuration.AzureBlobTenantManager"
|
||||
service="Orchard.Environment.Configuration.IShellSettingsManager">
|
||||
<parameters>
|
||||
<parameter name="account" value="devstoreaccount1"/>
|
||||
<parameter name="key" value="Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="/>
|
||||
<parameter name="container" value="mycontainer"/>
|
||||
</parameters>
|
||||
</component>-->
|
||||
|
||||
</components>
|
||||
</autofac>
|
||||
|
||||
</configuration>
|
||||
|
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
|
||||
</configSections>
|
||||
|
||||
<autofac defaultAssembly="Orchard.Framework">
|
||||
<components>
|
||||
|
||||
<component instance-scope="single-instance"
|
||||
type="Orchard.Specs.Hosting.TraceEnabledSessionFactoryBuilder, Orchard.Specs"
|
||||
service="Orchard.Data.Builders.ISessionFactoryBuilder, Orchard.Framework"/>
|
||||
|
||||
</components>
|
||||
</autofac>
|
||||
|
||||
</configuration>
|
||||
|
@@ -111,6 +111,9 @@ namespace Orchard.Specs.Hosting {
|
||||
if (index == HeaderSetCookie) {
|
||||
_details.ResponseHeaders.Add("Set-Cookie", value);
|
||||
}
|
||||
else if (index == HeaderLocation) {
|
||||
_details.ResponseHeaders.Add("Location", value);
|
||||
}
|
||||
else {
|
||||
_details.ResponseHeaders.Add("known header #" + index, value);
|
||||
}
|
||||
|
5
src/Orchard.Specs/Hosting/Simple.Web/Simple/Redir.aspx
Normal file
5
src/Orchard.Specs/Hosting/Simple.Web/Simple/Redir.aspx
Normal file
@@ -0,0 +1,5 @@
|
||||
<%@ Page %>
|
||||
|
||||
<%
|
||||
Response.Redirect("Page.aspx"); %>
|
||||
|
@@ -0,0 +1,24 @@
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
using NHibernate;
|
||||
using Orchard.Data.Builders;
|
||||
|
||||
namespace Orchard.Specs.Hosting {
|
||||
public class TraceEnabledSessionFactoryBuilder : ISessionFactoryBuilder {
|
||||
public TraceEnabledSessionFactoryBuilder() {
|
||||
|
||||
}
|
||||
public ISessionFactory BuildSessionFactory(SessionFactoryParameters parameters) {
|
||||
var builder = new TraceEnabledBuilder(parameters.DataFolder, parameters.ConnectionString);
|
||||
return builder.BuildSessionFactory(parameters);
|
||||
}
|
||||
|
||||
class TraceEnabledBuilder : SQLiteBuilder {
|
||||
public TraceEnabledBuilder(string dataFolder, string connectionString) : base(dataFolder, connectionString) {
|
||||
}
|
||||
protected override IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase) {
|
||||
var config = (SQLiteConfiguration)base.GetPersistenceConfigurer(createDatabase);
|
||||
return config.ShowSql();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,9 +5,28 @@
|
||||
|
||||
Scenario: Default site is listed
|
||||
Given I have installed Orchard
|
||||
And I have installed "Orchard.MultiTenancy"
|
||||
And I have installed "Orchard.MultiTenancy"
|
||||
When I go to "Admin/MultiTenancy"
|
||||
Then I should see "List of Site's Tenants"
|
||||
And I should see "Default"
|
||||
And the status should be 200 OK
|
||||
And I should see "<td>Default</td>"
|
||||
And the status should be 200 OK
|
||||
|
||||
Scenario: New tenant fields are required
|
||||
Given I have installed Orchard
|
||||
And I have installed "Orchard.MultiTenancy"
|
||||
When I go to "Admin/MultiTenancy/Add"
|
||||
And I hit "Save"
|
||||
Then I should see "is required"
|
||||
|
||||
Scenario: A new tenant is created
|
||||
Given I have installed Orchard
|
||||
And I have installed "Orchard.MultiTenancy"
|
||||
When I go to "Admin/MultiTenancy/Add"
|
||||
And I fill in
|
||||
| name | value |
|
||||
| Name | Scott |
|
||||
| DataProvider | SQLite |
|
||||
And I hit "Save"
|
||||
And I am redirected
|
||||
Then I should see "<td>Scott</td>"
|
||||
And the status should be 200 OK
|
||||
|
66
src/Orchard.Specs/MultiTenancy.feature.cs
generated
66
src/Orchard.Specs/MultiTenancy.feature.cs
generated
@@ -2,7 +2,7 @@
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.2.0.0
|
||||
// Runtime Version:2.0.50727.4927
|
||||
// Runtime Version:2.0.50727.4200
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -60,15 +60,73 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 7
|
||||
testRunner.Given("I have installed Orchard");
|
||||
#line 8
|
||||
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
|
||||
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
|
||||
#line 9
|
||||
testRunner.When("I go to \"Admin/MultiTenancy\"");
|
||||
#line 10
|
||||
testRunner.Then("I should see \"List of Site\'s Tenants\"");
|
||||
#line 11
|
||||
testRunner.And("I should see \"Default\"");
|
||||
testRunner.And("I should see \"<td>Default</td>\"");
|
||||
#line 12
|
||||
testRunner.And("the status should be 200 OK");
|
||||
testRunner.And("the status should be 200 OK");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("New tenant fields are required")]
|
||||
public virtual void NewTenantFieldsAreRequired()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("New tenant fields are required", ((string[])(null)));
|
||||
#line 14
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 15
|
||||
testRunner.Given("I have installed Orchard");
|
||||
#line 16
|
||||
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
|
||||
#line 17
|
||||
testRunner.When("I go to \"Admin/MultiTenancy/Add\"");
|
||||
#line 18
|
||||
testRunner.And("I hit \"Save\"");
|
||||
#line 19
|
||||
testRunner.Then("I should see \"is required\"");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("A new tenant is created")]
|
||||
public virtual void ANewTenantIsCreated()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant is created", ((string[])(null)));
|
||||
#line 21
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 22
|
||||
testRunner.Given("I have installed Orchard");
|
||||
#line 23
|
||||
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
|
||||
#line 24
|
||||
testRunner.When("I go to \"Admin/MultiTenancy/Add\"");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
"value"});
|
||||
table1.AddRow(new string[] {
|
||||
"Name",
|
||||
"Scott"});
|
||||
table1.AddRow(new string[] {
|
||||
"DataProvider",
|
||||
"SQLite"});
|
||||
#line 25
|
||||
testRunner.And("I fill in", ((string)(null)), table1);
|
||||
#line 29
|
||||
testRunner.And("I hit \"Save\"");
|
||||
#line 30
|
||||
testRunner.And("I am redirected");
|
||||
#line 31
|
||||
testRunner.Then("I should see \"<td>Scott</td>\"");
|
||||
#line 32
|
||||
testRunner.And("the status should be 200 OK");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
@@ -43,6 +43,14 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\autofac\Autofac.Integration.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\Castle Windsor 2.0\bin\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FluentNHibernate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\fluentnhibernate\FluentNHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FluentPath, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\fluentpath\FluentPath.dll</HintPath>
|
||||
@@ -51,8 +59,16 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\htmlagilitypack\HtmlAgilityPack.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\fluentnhibernate\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<Reference Include="Microsoft.VisualStudio.TeamSystem.Data.UnitTesting, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<Reference Include="NHibernate, Version=2.1.2.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\fluentnhibernate\NHibernate.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\nunit\nunit.framework.dll</HintPath>
|
||||
@@ -90,6 +106,7 @@
|
||||
<Compile Include="Bindings\OrchardSiteFactory.cs" />
|
||||
<Compile Include="Hosting\MessageSink.cs" />
|
||||
<Compile Include="Hosting\HostingTraceListener.cs" />
|
||||
<Compile Include="Hosting\TraceEnabledSessionFactoryBuilder.cs" />
|
||||
<Compile Include="Hosting\Simple.Web\HelloYetAgainHandler.cs" />
|
||||
<Compile Include="Hosting\RequestExtensions.cs" />
|
||||
<Compile Include="Hosting\RequestDetails.cs" />
|
||||
@@ -136,12 +153,18 @@
|
||||
<Content Include="Hosting\Orchard.Web\Themes\Web.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Hosting\Orchard.Web\Config\Sites.Default.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Hosting\Orchard.Web\Config\Diagnostics.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Content Include="Hosting\Simple.Web\Web.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Hosting\Orchard.Web\Config\Host.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="MultiTenancy.feature">
|
||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||
<LastGenOutput>MultiTenancy.feature.cs</LastGenOutput>
|
||||
@@ -239,6 +262,9 @@
|
||||
<Content Include="Hosting\Simple.Web\Simple\Cookie-Set.aspx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Hosting\Simple.Web\Simple\Redir.aspx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Hosting\Simple.Web\Simple\Results.aspx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@@ -4,45 +4,45 @@
|
||||
I want to setup a new site from the default screen
|
||||
|
||||
Scenario: Root request shows setup form
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Default.aspx"
|
||||
Then I should see "Welcome to Orchard"
|
||||
And I should see "Finish Setup"
|
||||
And the status should be 200 OK
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Default.aspx"
|
||||
Then I should see "Welcome to Orchard"
|
||||
And I should see "Finish Setup"
|
||||
And the status should be 200 OK
|
||||
|
||||
Scenario: Setup folder also shows setup form
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Setup"
|
||||
Then I should see "Welcome to Orchard"
|
||||
And I should see "Finish Setup"
|
||||
And the status should be 200 OK
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Setup"
|
||||
Then I should see "Welcome to Orchard"
|
||||
And I should see "Finish Setup"
|
||||
And the status should be 200 OK
|
||||
|
||||
Scenario: Some of the initial form values are required
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Setup"
|
||||
And I hit "Finish Setup"
|
||||
Then I should see "Site name is required"
|
||||
And I should see "Password is required"
|
||||
Given I have a clean site
|
||||
And I have module "Orchard.Setup"
|
||||
And I have theme "SafeMode"
|
||||
When I go to "/Setup"
|
||||
And I hit "Finish Setup"
|
||||
Then I should see "Site name is required"
|
||||
And I should see "Password is required"
|
||||
|
||||
Scenario: Calling setup on a brand new install
|
||||
Given I have a clean site with
|
||||
| extension | names |
|
||||
| module | Orchard.Setup, Orchard.Users, Orchard.Roles, Orchard.Pages, Orchard.Comments, TinyMce |
|
||||
| core | Common, Dashboard, Feeds, HomePage, Navigation, Scheduling, Settings, Themes, XmlRpc |
|
||||
| theme | SafeMode, Classic |
|
||||
And I am on "/Setup"
|
||||
When I fill in
|
||||
| name | value |
|
||||
| SiteName | My Site |
|
||||
| AdminPassword | 6655321 |
|
||||
And I hit "Finish Setup"
|
||||
And I go to "/Default.aspx"
|
||||
Then I should see "<h1>My Site</h1>"
|
||||
And I should see "Welcome, <strong>admin</strong>!"
|
||||
And I should see "you've successfully set-up your Orchard site"
|
||||
Given I have a clean site with
|
||||
| extension | names |
|
||||
| module | Orchard.Setup, Orchard.Users, Orchard.Roles, Orchard.Pages, Orchard.Comments, TinyMce |
|
||||
| core | Common, Dashboard, Feeds, HomePage, Navigation, Scheduling, Settings, Themes, XmlRpc |
|
||||
| theme | SafeMode, Classic |
|
||||
And I am on "/Setup"
|
||||
When I fill in
|
||||
| name | value |
|
||||
| SiteName | My Site |
|
||||
| AdminPassword | 6655321 |
|
||||
And I hit "Finish Setup"
|
||||
And I go to "/Default.aspx"
|
||||
Then I should see "<h1>My Site</h1>"
|
||||
And I should see "Welcome, <strong>admin</strong>!"
|
||||
And I should see "you've successfully set-up your Orchard site"
|
||||
|
60
src/Orchard.Specs/Setup.feature.cs
generated
60
src/Orchard.Specs/Setup.feature.cs
generated
@@ -2,7 +2,7 @@
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.2.0.0
|
||||
// Runtime Version:2.0.50727.4927
|
||||
// Runtime Version:2.0.50727.4200
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -58,19 +58,19 @@ namespace Orchard.Specs
|
||||
#line 6
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 7
|
||||
testRunner.Given("I have a clean site");
|
||||
testRunner.Given("I have a clean site");
|
||||
#line 8
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
#line 9
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
#line 10
|
||||
testRunner.When("I go to \"/Default.aspx\"");
|
||||
testRunner.When("I go to \"/Default.aspx\"");
|
||||
#line 11
|
||||
testRunner.Then("I should see \"Welcome to Orchard\"");
|
||||
testRunner.Then("I should see \"Welcome to Orchard\"");
|
||||
#line 12
|
||||
testRunner.And("I should see \"Finish Setup\"");
|
||||
testRunner.And("I should see \"Finish Setup\"");
|
||||
#line 13
|
||||
testRunner.And("the status should be 200 OK");
|
||||
testRunner.And("the status should be 200 OK");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
@@ -83,19 +83,19 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 15
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 16
|
||||
testRunner.Given("I have a clean site");
|
||||
testRunner.Given("I have a clean site");
|
||||
#line 17
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
#line 18
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
#line 19
|
||||
testRunner.When("I go to \"/Setup\"");
|
||||
testRunner.When("I go to \"/Setup\"");
|
||||
#line 20
|
||||
testRunner.Then("I should see \"Welcome to Orchard\"");
|
||||
testRunner.Then("I should see \"Welcome to Orchard\"");
|
||||
#line 21
|
||||
testRunner.And("I should see \"Finish Setup\"");
|
||||
testRunner.And("I should see \"Finish Setup\"");
|
||||
#line 22
|
||||
testRunner.And("the status should be 200 OK");
|
||||
testRunner.And("the status should be 200 OK");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
@@ -108,19 +108,19 @@ this.ScenarioSetup(scenarioInfo);
|
||||
#line 24
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 25
|
||||
testRunner.Given("I have a clean site");
|
||||
testRunner.Given("I have a clean site");
|
||||
#line 26
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
testRunner.And("I have module \"Orchard.Setup\"");
|
||||
#line 27
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
testRunner.And("I have theme \"SafeMode\"");
|
||||
#line 28
|
||||
testRunner.When("I go to \"/Setup\"");
|
||||
testRunner.When("I go to \"/Setup\"");
|
||||
#line 29
|
||||
testRunner.And("I hit \"Finish Setup\"");
|
||||
testRunner.And("I hit \"Finish Setup\"");
|
||||
#line 30
|
||||
testRunner.Then("I should see \"Site name is required\"");
|
||||
testRunner.Then("I should see \"Site name is required\"");
|
||||
#line 31
|
||||
testRunner.And("I should see \"Password is required\"");
|
||||
testRunner.And("I should see \"Password is required\"");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
@@ -148,9 +148,9 @@ this.ScenarioSetup(scenarioInfo);
|
||||
"theme",
|
||||
"SafeMode, Classic"});
|
||||
#line 34
|
||||
testRunner.Given("I have a clean site with", ((string)(null)), table1);
|
||||
testRunner.Given("I have a clean site with", ((string)(null)), table1);
|
||||
#line 39
|
||||
testRunner.And("I am on \"/Setup\"");
|
||||
testRunner.And("I am on \"/Setup\"");
|
||||
#line hidden
|
||||
TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] {
|
||||
"name",
|
||||
@@ -162,17 +162,17 @@ this.ScenarioSetup(scenarioInfo);
|
||||
"AdminPassword",
|
||||
"6655321"});
|
||||
#line 40
|
||||
testRunner.When("I fill in", ((string)(null)), table2);
|
||||
testRunner.When("I fill in", ((string)(null)), table2);
|
||||
#line 44
|
||||
testRunner.And("I hit \"Finish Setup\"");
|
||||
testRunner.And("I hit \"Finish Setup\"");
|
||||
#line 45
|
||||
testRunner.And("I go to \"/Default.aspx\"");
|
||||
testRunner.And("I go to \"/Default.aspx\"");
|
||||
#line 46
|
||||
testRunner.Then("I should see \"<h1>My Site</h1>\"");
|
||||
testRunner.Then("I should see \"<h1>My Site</h1>\"");
|
||||
#line 47
|
||||
testRunner.And("I should see \"Welcome, <strong>admin</strong>!\"");
|
||||
testRunner.And("I should see \"Welcome, <strong>admin</strong>!\"");
|
||||
#line 48
|
||||
testRunner.And("I should see \"you\'ve successfully set-up your Orchard site\"");
|
||||
testRunner.And("I should see \"you\'ve successfully set-up your Orchard site\"");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
@@ -44,3 +44,9 @@ Scenario: Cookies follow along your request
|
||||
When I go to "/simple/cookie-set.aspx"
|
||||
And I go to "/simple/cookie-show.aspx"
|
||||
Then I should see "foo:bar"
|
||||
|
||||
Scenario: Being redirected
|
||||
Given I have a clean site based on Simple.Web
|
||||
When I go to "/simple/redir.aspx"
|
||||
And I am redirected
|
||||
Then I should see "Hello again"
|
||||
|
21
src/Orchard.Specs/WebHosting.feature.cs
generated
21
src/Orchard.Specs/WebHosting.feature.cs
generated
@@ -2,7 +2,7 @@
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:1.2.0.0
|
||||
// Runtime Version:2.0.50727.4927
|
||||
// Runtime Version:2.0.50727.4200
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -175,6 +175,25 @@ this.ScenarioSetup(scenarioInfo);
|
||||
testRunner.And("I go to \"/simple/cookie-show.aspx\"");
|
||||
#line 46
|
||||
testRunner.Then("I should see \"foo:bar\"");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Being redirected")]
|
||||
public virtual void BeingRedirected()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Being redirected", ((string[])(null)));
|
||||
#line 48
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 49
|
||||
testRunner.Given("I have a clean site based on Simple.Web");
|
||||
#line 50
|
||||
testRunner.When("I go to \"/simple/redir.aspx\"");
|
||||
#line 51
|
||||
testRunner.And("I am redirected");
|
||||
#line 52
|
||||
testRunner.Then("I should see \"Hello again\"");
|
||||
#line hidden
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
@@ -1,109 +1,109 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Mvc.Routes;
|
||||
using Orchard.Tests.Stubs;
|
||||
//using System;
|
||||
//using System.Linq;
|
||||
//using System.Threading;
|
||||
//using System.Web.Mvc;
|
||||
//using System.Web.Routing;
|
||||
//using NUnit.Framework;
|
||||
//using Orchard.Mvc.Routes;
|
||||
//using Orchard.Tests.Stubs;
|
||||
|
||||
namespace Orchard.Tests.Mvc {
|
||||
[TestFixture]
|
||||
public class RouteCollectionPublisherTests {
|
||||
static RouteDescriptor Desc(string name, string url) {
|
||||
return new RouteDescriptor {Name = name, Route = new Route(url, new MvcRouteHandler())};
|
||||
}
|
||||
//namespace Orchard.Tests.Mvc {
|
||||
// [TestFixture]
|
||||
// public class RouteCollectionPublisherTests {
|
||||
// static RouteDescriptor Desc(string name, string url) {
|
||||
// return new RouteDescriptor {Name = name, Route = new Route(url, new MvcRouteHandler())};
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void PublisherShouldReplaceRoutes() {
|
||||
// //[Test]
|
||||
// //public void PublisherShouldReplaceRoutes() {
|
||||
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
publisher.Publish(new[] {Desc("barname", "bar"), Desc("quuxname", "quux")});
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] {Desc("barname", "bar"), Desc("quuxname", "quux")});
|
||||
|
||||
Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
}
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
|
||||
[Test]
|
||||
public void RoutesCanHaveNullOrEmptyNames() {
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// //[Test]
|
||||
// //public void RoutesCanHaveNullOrEmptyNames() {
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
publisher.Publish(new[] { Desc(null, "bar"), Desc(string.Empty, "quux") });
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] { Desc(null, "bar"), Desc(string.Empty, "quux") });
|
||||
|
||||
Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
}
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentException))]
|
||||
public void SameNameTwiceCausesExplosion() {
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// //[Test]
|
||||
// //[ExpectedException(typeof(ArgumentException))]
|
||||
// //public void SameNameTwiceCausesExplosion() {
|
||||
// // var routes = new RouteCollection();
|
||||
// // routes.MapRoute("foo", "{controller}");
|
||||
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
publisher.Publish(new[] {Desc("yarg", "bar"), Desc("yarg", "quux")});
|
||||
// // IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// // publisher.Publish(new[] {Desc("yarg", "bar"), Desc("yarg", "quux")});
|
||||
|
||||
Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
}
|
||||
// // Assert.That(routes.Count(), Is.EqualTo(2));
|
||||
// //}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ExplosionLeavesOriginalRoutesIntact() {
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// [Test]
|
||||
// public void ExplosionLeavesOriginalRoutesIntact() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
try {
|
||||
publisher.Publish(new[] { Desc("yarg", "bar"), Desc("yarg", "quux") });
|
||||
}
|
||||
catch (ArgumentException) {
|
||||
Assert.That(routes.Count(), Is.EqualTo(1));
|
||||
Assert.That(routes.OfType<Route>().Single().Url, Is.EqualTo("{controller}"));
|
||||
}
|
||||
}
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, new StubContainerProvider(null, null));
|
||||
// try {
|
||||
// publisher.Publish(new[] { Desc("yarg", "bar"), Desc("yarg", "quux") });
|
||||
// }
|
||||
// catch (ArgumentException) {
|
||||
// Assert.That(routes.Count(), Is.EqualTo(1));
|
||||
// Assert.That(routes.OfType<Route>().Single().Url, Is.EqualTo("{controller}"));
|
||||
// }
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void RoutesArePaintedWithConainerProviderAsTheyAreApplied() {
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// [Test]
|
||||
// public void RoutesArePaintedWithConainerProviderAsTheyAreApplied() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
|
||||
var containerProvider = new StubContainerProvider(null, null);
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
// var containerProvider = new StubContainerProvider(null, null);
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
// publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
|
||||
Assert.That(routes.OfType<Route>().Count(), Is.EqualTo(2));
|
||||
Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values).Count(), Is.EqualTo(2));
|
||||
Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values), Has.All.SameAs(containerProvider));
|
||||
}
|
||||
// Assert.That(routes.OfType<Route>().Count(), Is.EqualTo(2));
|
||||
// Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values).Count(), Is.EqualTo(2));
|
||||
// Assert.That(routes.OfType<Route>().SelectMany(r => r.DataTokens.Values), Has.All.SameAs(containerProvider));
|
||||
// }
|
||||
|
||||
[Test]
|
||||
public void WriteBlocksWhileReadIsInEffect() {
|
||||
var routes = new RouteCollection();
|
||||
routes.MapRoute("foo", "{controller}");
|
||||
// [Test]
|
||||
// public void WriteBlocksWhileReadIsInEffect() {
|
||||
// var routes = new RouteCollection();
|
||||
// routes.MapRoute("foo", "{controller}");
|
||||
|
||||
var containerProvider = new StubContainerProvider(null, null);
|
||||
IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
// var containerProvider = new StubContainerProvider(null, null);
|
||||
// IRoutePublisher publisher = new RoutePublisher(routes, containerProvider);
|
||||
|
||||
var readLock = routes.GetReadLock();
|
||||
// var readLock = routes.GetReadLock();
|
||||
|
||||
string where = "init";
|
||||
var action = new Action(() => {
|
||||
where = "before";
|
||||
publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
where = "after";
|
||||
});
|
||||
// string where = "init";
|
||||
// var action = new Action(() => {
|
||||
// where = "before";
|
||||
// publisher.Publish(new[] { Desc("barname", "bar"), Desc("quuxname", "quux") });
|
||||
// where = "after";
|
||||
// });
|
||||
|
||||
Assert.That(where, Is.EqualTo("init"));
|
||||
var async = action.BeginInvoke(null, null);
|
||||
Thread.Sleep(75);
|
||||
Assert.That(where, Is.EqualTo("before"));
|
||||
readLock.Dispose();
|
||||
Thread.Sleep(75);
|
||||
Assert.That(where, Is.EqualTo("after"));
|
||||
action.EndInvoke(async);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Assert.That(where, Is.EqualTo("init"));
|
||||
// var async = action.BeginInvoke(null, null);
|
||||
// Thread.Sleep(75);
|
||||
// Assert.That(where, Is.EqualTo("before"));
|
||||
// readLock.Dispose();
|
||||
// Thread.Sleep(75);
|
||||
// Assert.That(where, Is.EqualTo("after"));
|
||||
// action.EndInvoke(async);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
126
src/Orchard.Tests/Mvc/Routes/ShellRouteTests.cs
Normal file
126
src/Orchard.Tests/Mvc/Routes/ShellRouteTests.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Mvc.Routes;
|
||||
using Orchard.Tests.Stubs;
|
||||
|
||||
namespace Orchard.Tests.Mvc.Routes {
|
||||
[TestFixture]
|
||||
public class ShellRouteTests {
|
||||
private RouteCollection _routes;
|
||||
private ILifetimeScope _containerA;
|
||||
private ILifetimeScope _containerB;
|
||||
private ShellSettings _settingsA;
|
||||
private ShellSettings _settingsB;
|
||||
private IContainer _rootContainer;
|
||||
|
||||
[Test]
|
||||
public void FactoryMethodWillCreateShellRoutes() {
|
||||
var settings = new ShellSettings { Name = "Alpha" };
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
builder.Register(ctx => settings);
|
||||
|
||||
var container = builder.Build();
|
||||
var buildShellRoute = container.Resolve<Func<RouteBase, ShellRoute>>();
|
||||
|
||||
var routeA = new Route("foo", new MvcRouteHandler());
|
||||
var route1 = buildShellRoute(routeA);
|
||||
|
||||
var routeB = new Route("bar", new MvcRouteHandler()) {
|
||||
DataTokens = new RouteValueDictionary { { "area", "Beta" } }
|
||||
};
|
||||
var route2 = buildShellRoute(routeB);
|
||||
|
||||
Assert.That(route1, Is.Not.SameAs(route2));
|
||||
|
||||
Assert.That(route1.ShellSettingsName, Is.EqualTo("Alpha"));
|
||||
Assert.That(route1.Area, Is.Null);
|
||||
|
||||
Assert.That(route2.ShellSettingsName, Is.EqualTo("Alpha"));
|
||||
Assert.That(route2.Area, Is.EqualTo("Beta"));
|
||||
}
|
||||
|
||||
private void Init() {
|
||||
_settingsA = new ShellSettings {Name = "Alpha"};
|
||||
_settingsB = new ShellSettings {Name = "Beta"};
|
||||
_routes = new RouteCollection();
|
||||
|
||||
var rootBuilder = new ContainerBuilder();
|
||||
rootBuilder.Register(ctx => _routes);
|
||||
rootBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
rootBuilder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
|
||||
|
||||
_rootContainer = rootBuilder.Build();
|
||||
_containerA = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsA);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
|
||||
});
|
||||
|
||||
_containerB = _rootContainer.BeginLifetimeScope(
|
||||
builder => {
|
||||
builder.Register(ctx => _settingsB);
|
||||
builder.RegisterType<RoutePublisher>().As<IRoutePublisher>();
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RoutePublisherReplacesOnlyNamedShellsRoutes() {
|
||||
Init();
|
||||
|
||||
var routeA = new Route("foo", new MvcRouteHandler());
|
||||
var routeB = new Route("bar", new MvcRouteHandler());
|
||||
var routeC = new Route("quux", new MvcRouteHandler());
|
||||
|
||||
_containerA.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeA}});
|
||||
|
||||
_containerB.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeB}});
|
||||
|
||||
Assert.That(_routes.Count(), Is.EqualTo(2));
|
||||
|
||||
_containerA.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeC}});
|
||||
|
||||
Assert.That(_routes.Count(), Is.EqualTo(2));
|
||||
|
||||
_containerB.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {
|
||||
new RouteDescriptor {Priority = 0, Route = routeA},
|
||||
new RouteDescriptor {Priority = 0, Route = routeB},
|
||||
});
|
||||
|
||||
Assert.That(_routes.Count(), Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MatchingRouteToActiveShellTableWillLimitTheAbilityToMatchRoutes() {
|
||||
Init();
|
||||
|
||||
var routeA = new Route("foo", new MvcRouteHandler());
|
||||
var routeB = new Route("bar", new MvcRouteHandler());
|
||||
var routeC = new Route("quux", new MvcRouteHandler());
|
||||
|
||||
_containerA.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeA}});
|
||||
|
||||
_containerB.Resolve<IRoutePublisher>().Publish(
|
||||
new[] {new RouteDescriptor {Priority = 0, Route = routeB}});
|
||||
|
||||
var httpContext = new StubHttpContext("~/foo");
|
||||
var routeData = _routes.GetRouteData(httpContext);
|
||||
Assert.That(routeData, Is.Null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -167,6 +167,7 @@
|
||||
<Compile Include="Environment\OrchardStarterTests.cs" />
|
||||
<Compile Include="Environment\ShellBuilders\DefaultShellContainerFactoryTests.cs" />
|
||||
<Compile Include="Environment\ShellBuilders\DefaultShellContextFactoryTests.cs" />
|
||||
<Compile Include="Mvc\Routes\ShellRouteTests.cs" />
|
||||
<Compile Include="Utility\ContainerExtensions.cs" />
|
||||
<Compile Include="Environment\TestDependencies\TestDependency.cs" />
|
||||
<Compile Include="Environment\Topology\DefaultShellDescriptorCacheTests.cs" />
|
||||
|
@@ -15,9 +15,8 @@ namespace Orchard.Web {
|
||||
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
|
||||
// visit http://go.microsoft.com/?LinkId=9394801
|
||||
|
||||
public class MvcApplication : HttpApplication, IContainerProviderAccessor {
|
||||
public class MvcApplication : HttpApplication {
|
||||
private static IOrchardHost _host;
|
||||
private static IContainerProvider _containerProvider;
|
||||
|
||||
public static void RegisterRoutes(RouteCollection routes) {
|
||||
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
|
||||
@@ -31,11 +30,6 @@ namespace Orchard.Web {
|
||||
new Version("2.0.50129.0")/*MVC2 RC2 file version #*/,
|
||||
new Version("2.0.41211.0")/*MVC2 RC file version #*/);
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterControllers(Assembly.GetExecutingAssembly());
|
||||
_containerProvider = new ContainerProvider(builder.Build());
|
||||
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(ContainerProvider));
|
||||
|
||||
RegisterRoutes(RouteTable.Routes);
|
||||
|
||||
_host = OrchardStarter.CreateHost(MvcSingletons);
|
||||
@@ -108,14 +102,5 @@ namespace Orchard.Web {
|
||||
builder.RegisterInstance(ViewEngines.Engines);
|
||||
}
|
||||
|
||||
#region Implementation of IContainerProviderAccessor
|
||||
|
||||
public IContainerProvider ContainerProvider {
|
||||
get {
|
||||
return _containerProvider;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -33,10 +33,8 @@ namespace Orchard.MultiTenancy.Controllers {
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("Add")]
|
||||
public ActionResult AddPOST() {
|
||||
var viewModel = new TenantsAddViewModel();
|
||||
public ActionResult AddPOST(TenantsAddViewModel viewModel) {
|
||||
try {
|
||||
UpdateModel(viewModel);
|
||||
if (!Services.Authorizer.Authorize(Permissions.ManageTenants, T("Couldn't create tenant")))
|
||||
return new HttpUnauthorizedResult();
|
||||
_tenantService.CreateTenant(
|
||||
|
@@ -144,7 +144,6 @@
|
||||
</httpHandlers>
|
||||
|
||||
<httpModules>
|
||||
<add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
|
||||
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
|
||||
</httpModules>
|
||||
@@ -178,7 +177,6 @@
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
|
||||
<modules runAllManagedModulesForAllRequests="true">
|
||||
<add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
|
||||
<remove name="ScriptModule" />
|
||||
<remove name="UrlRoutingModule" />
|
||||
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
|
||||
|
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
|
||||
namespace Orchard.Environment.AutofacUtil {
|
||||
public class LifetimeScopeContainer : IContainer {
|
||||
private readonly ILifetimeScope _lifetimeScope;
|
||||
|
||||
public LifetimeScopeContainer(ILifetimeScope lifetimeScope) {
|
||||
_lifetimeScope = lifetimeScope;
|
||||
}
|
||||
|
||||
public object Resolve(IComponentRegistration registration, IEnumerable<Parameter> parameters) {
|
||||
return _lifetimeScope.Resolve(registration, parameters);
|
||||
}
|
||||
|
||||
public IComponentRegistry ComponentRegistry {
|
||||
get { return _lifetimeScope.ComponentRegistry; }
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope() {
|
||||
return _lifetimeScope.BeginLifetimeScope();
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(object tag) {
|
||||
return _lifetimeScope.BeginLifetimeScope(tag);
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(Action<ContainerBuilder> configurationAction) {
|
||||
return _lifetimeScope.BeginLifetimeScope(configurationAction);
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(object tag, Action<ContainerBuilder> configurationAction) {
|
||||
return _lifetimeScope.BeginLifetimeScope(tag, configurationAction);
|
||||
}
|
||||
|
||||
public IDisposer Disposer {
|
||||
get { return _lifetimeScope.Disposer; }
|
||||
}
|
||||
|
||||
public object Tag {
|
||||
get { return _lifetimeScope.Tag; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,22 +13,23 @@ using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public class DefaultOrchardHost : IOrchardHost {
|
||||
//private readonly IContainerProvider _containerProvider;
|
||||
private readonly ControllerBuilder _controllerBuilder;
|
||||
|
||||
private readonly IShellSettingsManager _shellSettingsManager;
|
||||
private readonly IShellContextFactory _shellContextFactory;
|
||||
private readonly IRunningShellTable _runningShellTable;
|
||||
|
||||
private IEnumerable<ShellContext> _current;
|
||||
|
||||
public DefaultOrchardHost(
|
||||
//IContainerProvider containerProvider,
|
||||
IShellSettingsManager shellSettingsManager,
|
||||
IShellContextFactory shellContextFactory,
|
||||
IRunningShellTable runningShellTable,
|
||||
ControllerBuilder controllerBuilder) {
|
||||
//_containerProvider = containerProvider;
|
||||
_shellSettingsManager = shellSettingsManager;
|
||||
_shellContextFactory = shellContextFactory;
|
||||
_runningShellTable = runningShellTable;
|
||||
_controllerBuilder = controllerBuilder;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
@@ -54,10 +55,12 @@ namespace Orchard.Environment {
|
||||
|
||||
|
||||
void IOrchardHost.BeginRequest() {
|
||||
Logger.Debug("BeginRequest");
|
||||
BeginRequest();
|
||||
}
|
||||
|
||||
void IOrchardHost.EndRequest() {
|
||||
Logger.Debug("EndRequest");
|
||||
EndRequest();
|
||||
}
|
||||
|
||||
@@ -81,13 +84,15 @@ namespace Orchard.Environment {
|
||||
settings => {
|
||||
var context = CreateShellContext(settings);
|
||||
context.Shell.Activate();
|
||||
_runningShellTable.Add(settings);
|
||||
return context;
|
||||
});
|
||||
}
|
||||
|
||||
var setupContext = CreateSetupContext();
|
||||
setupContext.Shell.Activate();
|
||||
return new[] {setupContext};
|
||||
_runningShellTable.Add(setupContext.Settings);
|
||||
return new[] { setupContext };
|
||||
}
|
||||
|
||||
ShellContext CreateSetupContext() {
|
||||
@@ -105,7 +110,6 @@ namespace Orchard.Environment {
|
||||
}
|
||||
|
||||
protected virtual void EndRequest() {
|
||||
//_containerProvider.EndRequestLifetime();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -123,7 +123,7 @@ namespace Orchard.Environment.Extensions {
|
||||
var featureName = featureDescriptor.Name;
|
||||
string extensionName = GetExtensionForFeature(featureName);
|
||||
if (extensionName == null) throw new ArgumentException(T("Feature ") + featureName + T(" was not found in any of the installed extensions"));
|
||||
var extension = ActiveExtensions_Obsolete().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault();
|
||||
var extension = BuildActiveExtensions().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault();
|
||||
if (extension == null) throw new InvalidOperationException(T("Extension ") + extensionName + T(" is not active"));
|
||||
|
||||
var extensionTypes = extension.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract);
|
||||
|
@@ -1,17 +1,13 @@
|
||||
using Autofac;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Environment.AutofacUtil;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
|
||||
class FiniteContainerProvider : IContainerProvider {
|
||||
public FiniteContainerProvider(ILifetimeScope applicationContainer) {
|
||||
//ApplicationContainer = applicationContainer;
|
||||
|
||||
RequestLifetime = applicationContainer.BeginLifetimeScope(
|
||||
builder=> {
|
||||
// also inject this instance in case anyone asks for the container provider
|
||||
builder.Register(ctx => this).As<IContainerProvider>();
|
||||
});
|
||||
ApplicationContainer = new LifetimeScopeContainer(applicationContainer);
|
||||
RequestLifetime = ApplicationContainer.BeginLifetimeScope("httpRequest");
|
||||
}
|
||||
|
||||
public void EndRequestLifetime() {
|
||||
|
@@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Web.Hosting;
|
||||
using Autofac;
|
||||
using Autofac.Configuration;
|
||||
using Autofac.Core;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Environment.AutofacUtil;
|
||||
using Orchard.Environment.Configuration;
|
||||
@@ -63,12 +61,13 @@ namespace Orchard.Environment {
|
||||
}
|
||||
}
|
||||
|
||||
builder.RegisterType<RunningShellTable>().As<IRunningShellTable>().SingleInstance();
|
||||
builder.RegisterType<DefaultOrchardShell>().As<IOrchardShell>().InstancePerMatchingLifetimeScope("shell");
|
||||
|
||||
// The container provider gives you access to the lowest container at the time,
|
||||
// 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
|
||||
builder.RegisterType<ContainerProvider>().As<IContainerProvider>().InstancePerLifetimeScope();
|
||||
//builder.RegisterType<ContainerProvider>().As<IContainerProvider>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
|
||||
@@ -91,49 +90,6 @@ namespace Orchard.Environment {
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public class LifetimeScopeContainer : IContainer {
|
||||
private readonly ILifetimeScope _lifetimeScope;
|
||||
|
||||
public LifetimeScopeContainer(ILifetimeScope lifetimeScope) {
|
||||
_lifetimeScope = lifetimeScope;
|
||||
}
|
||||
|
||||
public object Resolve(IComponentRegistration registration, IEnumerable<Parameter> parameters) {
|
||||
return _lifetimeScope.Resolve(registration, parameters);
|
||||
}
|
||||
|
||||
public IComponentRegistry ComponentRegistry {
|
||||
get { return _lifetimeScope.ComponentRegistry; }
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope() {
|
||||
return _lifetimeScope.BeginLifetimeScope();
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(object tag) {
|
||||
return _lifetimeScope.BeginLifetimeScope(tag);
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(Action<ContainerBuilder> configurationAction) {
|
||||
return _lifetimeScope.BeginLifetimeScope(configurationAction);
|
||||
}
|
||||
|
||||
public ILifetimeScope BeginLifetimeScope(object tag, Action<ContainerBuilder> configurationAction) {
|
||||
return _lifetimeScope.BeginLifetimeScope(tag, configurationAction);
|
||||
}
|
||||
|
||||
public IDisposer Disposer {
|
||||
get { return _lifetimeScope.Disposer; }
|
||||
}
|
||||
|
||||
public object Tag {
|
||||
get { return _lifetimeScope.Tag; }
|
||||
}
|
||||
}
|
||||
|
||||
public static IOrchardHost CreateHost(Action<ContainerBuilder> registrations) {
|
||||
var container = CreateHostContainer(registrations);
|
||||
return container.Resolve<IOrchardHost>();
|
||||
|
33
src/Orchard/Environment/RunningShellTable.cs
Normal file
33
src/Orchard/Environment/RunningShellTable.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IRunningShellTable {
|
||||
void Add(ShellSettings settings);
|
||||
IEnumerable<ShellSettings> List();
|
||||
ShellSettings Match(HttpContextBase httpContext);
|
||||
}
|
||||
|
||||
public class RunningShellTable : IRunningShellTable {
|
||||
private IEnumerable<ShellSettings> _shells = Enumerable.Empty<ShellSettings>();
|
||||
|
||||
public void Add(ShellSettings settings) {
|
||||
_shells = _shells
|
||||
.Where(s=>s.Name != settings.Name)
|
||||
.Concat(new[] { settings })
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<ShellSettings> List() {
|
||||
return _shells;
|
||||
}
|
||||
|
||||
public ShellSettings Match(HttpContextBase httpContext) {
|
||||
return _shells.SingleOrDefault(settings => settings.Name == "Default");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Hosting;
|
||||
using System.Web.Mvc;
|
||||
using Autofac;
|
||||
using Autofac.Builder;
|
||||
using Autofac.Configuration;
|
||||
using Autofac.Core;
|
||||
using Autofac.Features.Indexed;
|
||||
using Autofac.Integration.Web.Mvc;
|
||||
@@ -83,6 +86,10 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
.InstancePerDependency()
|
||||
.InjectActionInvoker();
|
||||
}
|
||||
|
||||
var optionalHostConfig = HostingEnvironment.MapPath("~/Config/Sites." + settings.Name + ".config");
|
||||
if (File.Exists(optionalHostConfig))
|
||||
builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig));
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -90,7 +90,7 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
public ShellContext CreateSetupContext() {
|
||||
Logger.Warning("No shell settings available. Creating shell context for setup");
|
||||
|
||||
var settings = new ShellSettings { Name = "__Orchard__Setup__" };
|
||||
var settings = new ShellSettings { Name = "Default" };
|
||||
|
||||
var descriptor = new ShellDescriptor {
|
||||
SerialNumber = -1,
|
||||
|
@@ -4,12 +4,14 @@ using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Orchard.Mvc.Filters;
|
||||
using Orchard.Mvc.Routes;
|
||||
|
||||
namespace Orchard.Mvc {
|
||||
public class MvcModule : Module {
|
||||
|
||||
protected override void Load(ContainerBuilder moduleBuilder) {
|
||||
moduleBuilder.RegisterType<FilterResolvingActionInvoker>().As<IActionInvoker>().InstancePerDependency();
|
||||
moduleBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||
|
||||
moduleBuilder.Register(ctx => HttpContextBaseFactory(ctx)).As<HttpContextBase>().InstancePerDependency();
|
||||
moduleBuilder.Register(ctx => RequestContextFactory(ctx)).As<RequestContext>().InstancePerDependency();
|
||||
|
@@ -1,20 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Routing;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Mvc.Routes {
|
||||
public class RoutePublisher : IRoutePublisher {
|
||||
private readonly RouteCollection _routeCollection;
|
||||
private readonly IContainerProvider _containerProvider;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly Func<RouteBase, ShellRoute> _shellRouteFactory;
|
||||
|
||||
public RoutePublisher(RouteCollection routeCollection, IContainerProvider containerProvider) {
|
||||
public RoutePublisher(
|
||||
RouteCollection routeCollection,
|
||||
ShellSettings shellSettings,
|
||||
Func<RouteBase, ShellRoute> shellRouteFactory) {
|
||||
_routeCollection = routeCollection;
|
||||
_containerProvider = containerProvider;
|
||||
_shellSettings = shellSettings;
|
||||
_shellRouteFactory = shellRouteFactory;
|
||||
}
|
||||
|
||||
public void Publish(IEnumerable<RouteDescriptor> routes) {
|
||||
var routesArray = routes.OrderByDescending(r=>r.Priority).ToArray();
|
||||
var routesArray = routes.OrderByDescending(r => r.Priority).ToArray();
|
||||
|
||||
// this is not called often, but is intended to surface problems before
|
||||
// the actual collection is modified
|
||||
@@ -24,18 +30,19 @@ namespace Orchard.Mvc.Routes {
|
||||
|
||||
using (_routeCollection.GetWriteLock()) {
|
||||
// existing routes are removed while the collection is briefly inaccessable
|
||||
_routeCollection.Clear();
|
||||
var cropArray = _routeCollection
|
||||
.OfType<ShellRoute>()
|
||||
.Where(sr => sr.ShellSettingsName == _shellSettings.Name)
|
||||
.ToArray();
|
||||
|
||||
// new routes are added
|
||||
foreach (var route in routesArray) {
|
||||
_routeCollection.Add(route.Name, route.Route);
|
||||
foreach(var crop in cropArray) {
|
||||
_routeCollection.Remove(crop);
|
||||
}
|
||||
|
||||
// and painted with the IContainerProvider if it's type has data tokens
|
||||
foreach (var route in routesArray.Select(d => d.Route).OfType<Route>()) {
|
||||
if (route.DataTokens == null)
|
||||
route.DataTokens = new RouteValueDictionary();
|
||||
route.DataTokens["IContainerProvider"] = _containerProvider;
|
||||
// new routes are added
|
||||
foreach (var routeDescriptor in routesArray) {
|
||||
//_routeCollection.Add(route.Name, _shellRouteFactory(_shellSettings.Name, route.Route));
|
||||
_routeCollection.Add(routeDescriptor.Name, _shellRouteFactory(routeDescriptor.Route));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
146
src/Orchard/Mvc/Routes/ShellRoute.cs
Normal file
146
src/Orchard/Mvc/Routes/ShellRoute.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Web.SessionState;
|
||||
using Autofac;
|
||||
using Autofac.Integration.Web;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.AutofacUtil;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Mvc.Routes {
|
||||
|
||||
public class ShellRoute : RouteBase, IRouteWithArea {
|
||||
private readonly RouteBase _route;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IContainer _container;
|
||||
private readonly IRunningShellTable _runningShellTable;
|
||||
|
||||
public ShellRoute(RouteBase route, ShellSettings shellSettings, ILifetimeScope shellLifetimeScope, IRunningShellTable runningShellTable) {
|
||||
_route = route;
|
||||
_shellSettings = shellSettings;
|
||||
_runningShellTable = runningShellTable;
|
||||
_container = new LifetimeScopeContainer(shellLifetimeScope);
|
||||
|
||||
var routeWithArea = route as IRouteWithArea;
|
||||
if (routeWithArea != null) {
|
||||
Area = routeWithArea.Area;
|
||||
}
|
||||
|
||||
var routeWithDataTokens = route as Route;
|
||||
if ((routeWithDataTokens != null) && (routeWithDataTokens.DataTokens != null)) {
|
||||
Area = (routeWithDataTokens.DataTokens["area"] as string);
|
||||
}
|
||||
}
|
||||
|
||||
public string ShellSettingsName { get { return _shellSettings.Name; } }
|
||||
public string Area { get; private set; }
|
||||
|
||||
public override RouteData GetRouteData(HttpContextBase httpContext) {
|
||||
// locate appropriate shell settings for request
|
||||
var settings = _runningShellTable.Match(httpContext);
|
||||
|
||||
// only proceed if there was a match, and it was for this client
|
||||
if (settings == null || settings.Name != _shellSettings.Name)
|
||||
return null;
|
||||
|
||||
// route didn't match anyway
|
||||
var routeData = _route.GetRouteData(httpContext);
|
||||
if (routeData == null)
|
||||
return null;
|
||||
|
||||
// otherwise paint wrap handler and return it
|
||||
routeData.RouteHandler = new RouteHandler(_container, routeData.RouteHandler);
|
||||
return routeData;
|
||||
}
|
||||
|
||||
|
||||
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {
|
||||
// todo - ignore conditionally
|
||||
|
||||
var virtualPath = _route.GetVirtualPath(requestContext, values);
|
||||
if (virtualPath == null)
|
||||
return null;
|
||||
|
||||
return virtualPath;
|
||||
}
|
||||
|
||||
|
||||
class RouteHandler : IRouteHandler {
|
||||
private readonly IContainer _container;
|
||||
private readonly IRouteHandler _routeHandler;
|
||||
|
||||
public RouteHandler(IContainer container, IRouteHandler routeHandler) {
|
||||
_container = container;
|
||||
_routeHandler = routeHandler;
|
||||
}
|
||||
|
||||
public IHttpHandler GetHttpHandler(RequestContext requestContext) {
|
||||
var httpHandler = _routeHandler.GetHttpHandler(requestContext);
|
||||
return new HttpAsyncHandler(
|
||||
_container,
|
||||
requestContext,
|
||||
(IHttpAsyncHandler)httpHandler);
|
||||
}
|
||||
}
|
||||
|
||||
class HttpAsyncHandler : IHttpAsyncHandler, IRequiresSessionState, IContainerProvider {
|
||||
private readonly RequestContext _requestContext;
|
||||
private readonly IHttpAsyncHandler _httpAsyncHandler;
|
||||
|
||||
public HttpAsyncHandler(IContainer applicationContainer, RequestContext requestContext, IHttpAsyncHandler httpAsyncHandler) {
|
||||
ApplicationContainer = applicationContainer;
|
||||
_requestContext = requestContext;
|
||||
_httpAsyncHandler = httpAsyncHandler;
|
||||
}
|
||||
|
||||
public bool IsReusable {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public void ProcessRequest(HttpContext context) {
|
||||
BeginRequestLifetime();
|
||||
try {
|
||||
_httpAsyncHandler.ProcessRequest(context);
|
||||
}
|
||||
finally {
|
||||
EndRequestLifetime();
|
||||
}
|
||||
}
|
||||
|
||||
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
|
||||
BeginRequestLifetime();
|
||||
try {
|
||||
return _httpAsyncHandler.BeginProcessRequest(context, cb, extraData);
|
||||
}
|
||||
catch {
|
||||
EndRequestLifetime();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void EndProcessRequest(IAsyncResult result) {
|
||||
try {
|
||||
_httpAsyncHandler.EndProcessRequest(result);
|
||||
}
|
||||
finally {
|
||||
EndRequestLifetime();
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginRequestLifetime() {
|
||||
RequestLifetime = ApplicationContainer.BeginLifetimeScope("httpRequest");
|
||||
_requestContext.RouteData.DataTokens["IContainerProvider"] = this;
|
||||
}
|
||||
|
||||
public void EndRequestLifetime() {
|
||||
_requestContext.RouteData.DataTokens.Remove("IContainerProvider");
|
||||
RequestLifetime.Dispose();
|
||||
}
|
||||
|
||||
public IContainer ApplicationContainer { get; set; }
|
||||
public ILifetimeScope RequestLifetime { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -161,6 +161,8 @@
|
||||
<Compile Include="Data\Builders\SqlServerBuilder.cs" />
|
||||
<Compile Include="Data\Conventions\StringLengthConvention.cs" />
|
||||
<Compile Include="Data\SessionFactoryHolder.cs" />
|
||||
<Compile Include="Environment\AutofacUtil\LifetimeScopeContainer.cs" />
|
||||
<Compile Include="Environment\RunningShellTable.cs" />
|
||||
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyContext.cs" />
|
||||
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyExtensions.cs" />
|
||||
<Compile Include="Environment\AutofacUtil\DynamicProxy2\ConstructorFinderWrapper.cs" />
|
||||
@@ -191,6 +193,7 @@
|
||||
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
|
||||
<Compile Include="Mvc\Html\FileRegistrationContextExtensions.cs" />
|
||||
<Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" />
|
||||
<Compile Include="Mvc\Routes\ShellRoute.cs" />
|
||||
<Compile Include="Mvc\ViewModels\AdaptedViewModel.cs" />
|
||||
<Compile Include="Mvc\ViewUserControl.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
|
Reference in New Issue
Block a user