mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -89,6 +89,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Roles\Controllers\AdminControllerTests.cs" />
|
||||
<Compile Include="Roles\Services\RoleServiceTests.cs" />
|
||||
<Compile Include="Setup\SetupControllerTests.cs" />
|
||||
<Compile Include="Values.cs" />
|
||||
<Compile Include="Users\Controllers\AdminControllerTests.cs" />
|
||||
<Compile Include="Users\Services\MembershipServiceTests.cs" />
|
||||
@@ -113,6 +114,10 @@
|
||||
<Project>{D10AD48F-407D-4DB5-A328-173EC7CB010F}</Project>
|
||||
<Name>Orchard.Roles</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Setup\Orchard.Setup.csproj">
|
||||
<Project>{8C7FCBC2-E6E1-405E-BFB5-D8D9E67A09C4}</Project>
|
||||
<Name>Orchard.Setup</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Users\Orchard.Users.csproj">
|
||||
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
|
||||
<Name>Orchard.Users</Name>
|
||||
|
110
src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs
Normal file
110
src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Autofac.Builder;
|
||||
using JetBrains.Annotations;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Setup.Controllers;
|
||||
using Orchard.Setup.ViewModels;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Tests.Modules.Setup {
|
||||
[TestFixture, Ignore("this can't be made to work")]
|
||||
public class SetupControllerTests {
|
||||
private string _tempFolder;
|
||||
private IContainer _container;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_tempFolder = Path.GetTempFileName();
|
||||
File.Delete(_tempFolder);
|
||||
Directory.CreateDirectory(_tempFolder);
|
||||
|
||||
var hostContainer = OrchardStarter.CreateHostContainer(builder => {
|
||||
builder.Register(new ControllerBuilder());
|
||||
builder.Register(new ViewEngineCollection { new WebFormViewEngine() });
|
||||
builder.Register(new RouteCollection());
|
||||
builder.Register(new ModelBinderDictionary());
|
||||
});
|
||||
|
||||
hostContainer.Resolve<IAppDataFolder>().SetBasePath(_tempFolder);
|
||||
|
||||
var host = (DefaultOrchardHost)hostContainer.Resolve<IOrchardHost>();
|
||||
_container = host.CreateShellContainer();
|
||||
_container.Build(builder => {
|
||||
builder.Register<SetupController>();
|
||||
});
|
||||
|
||||
|
||||
//var builder = new ContainerBuilder();
|
||||
//builder.Register<SetupController>();
|
||||
//builder.Register<Notifier>().As<INotifier>();
|
||||
//builder.Register<DefaultOrchardHost>().As<IOrchardHost>();
|
||||
//builder.Register<DatabaseMigrationManager>().As<IDatabaseMigrationManager>();
|
||||
//builder.Register<ShellSettingsLoader>().As<IShellSettingsLoader>();
|
||||
//builder.Register<TestAppDataFolder>().As<IAppDataFolder>();
|
||||
//_container = builder.Build();
|
||||
}
|
||||
|
||||
private string GetMessages() {
|
||||
var notifier = _container.Resolve<INotifier>();
|
||||
return notifier.List().Aggregate("", (a, b) => a + b.Message.ToString());
|
||||
}
|
||||
|
||||
private SetupViewModel GetTestSetupModel() {
|
||||
return new SetupViewModel {
|
||||
AdminUsername = "test1",
|
||||
AdminPassword = "test2",
|
||||
DatabaseOptions = true,
|
||||
SiteName = "test3"
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IndexNormallyReturnsWithDefaultAdminUsername() {
|
||||
var controller = _container.Resolve<SetupController>();
|
||||
var result = controller.Index(null);
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Is.TypeOf<ViewResult>());
|
||||
|
||||
var viewResult = (ViewResult)result;
|
||||
Assert.That(viewResult.ViewData.Model, Is.TypeOf<SetupViewModel>());
|
||||
|
||||
var model2 = (SetupViewModel)viewResult.ViewData.Model;
|
||||
Assert.That(model2.AdminUsername, Is.EqualTo("admin"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetupShouldCreateShellSettingsFile() {
|
||||
var model = GetTestSetupModel();
|
||||
var controller = _container.Resolve<SetupController>();
|
||||
var result = controller.IndexPOST(model);
|
||||
|
||||
Assert.That(GetMessages(), Is.StringContaining("Setup succeeded"));
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Is.TypeOf<RedirectResult>());
|
||||
Assert.That(File.Exists(Path.Combine(_tempFolder, "Sites\\default.txt")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuiltinDatabaseShouldCreateSQLiteFile() {
|
||||
var model = GetTestSetupModel();
|
||||
var controller = _container.Resolve<SetupController>();
|
||||
var result = controller.IndexPOST(model);
|
||||
|
||||
Assert.That(GetMessages(), Is.StringContaining("Setup succeeded"));
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result, Is.TypeOf<RedirectResult>());
|
||||
Assert.That(File.Exists(Path.Combine(_tempFolder, "Sites\\default\\orchard.db")));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
105
src/Orchard.Tests/Data/Builders/SessionFactoryBuilderTests.cs
Normal file
105
src/Orchard.Tests/Data/Builders/SessionFactoryBuilderTests.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Tests.Records;
|
||||
|
||||
namespace Orchard.Tests.Data.Builders {
|
||||
[TestFixture]
|
||||
public class SessionFactoryBuilderTests {
|
||||
private string _tempDataFolder;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var tempFilePath = Path.GetTempFileName();
|
||||
File.Delete(tempFilePath);
|
||||
Directory.CreateDirectory(tempFilePath);
|
||||
_tempDataFolder = tempFilePath;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Term() {
|
||||
try { Directory.Delete(_tempDataFolder, true); }
|
||||
catch (IOException) { }
|
||||
}
|
||||
|
||||
private static void CreateSqlServerDatabase(string databasePath) {
|
||||
var databaseName = Path.GetFileNameWithoutExtension(databasePath);
|
||||
using (var connection = new SqlConnection(
|
||||
"Data Source=.\\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=true;User Instance=True;")) {
|
||||
connection.Open();
|
||||
using (var command = connection.CreateCommand()) {
|
||||
command.CommandText =
|
||||
"CREATE DATABASE " + databaseName +
|
||||
" ON PRIMARY (NAME=" + databaseName +
|
||||
", FILENAME='" + databasePath.Replace("'", "''") + "')";
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
command.CommandText =
|
||||
"EXEC sp_detach_db '" + databaseName + "', 'true'";
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void SQLiteSchemaShouldBeGeneratedAndUsable() {
|
||||
var recordDescriptors = new[] {
|
||||
new RecordDescriptor {Prefix = "Hello", Type = typeof (Foo)}
|
||||
};
|
||||
var manager = (ISessionFactoryBuilder)new SessionFactoryBuilder();
|
||||
var sessionFactory = manager.BuildSessionFactory(new SessionFactoryParameters {
|
||||
Provider = "SQLite",
|
||||
DataFolder = _tempDataFolder,
|
||||
UpdateSchema = true,
|
||||
RecordDescriptors = recordDescriptors
|
||||
});
|
||||
|
||||
|
||||
var session = sessionFactory.OpenSession();
|
||||
var foo = new Foo { Name = "hi there" };
|
||||
session.Save(foo);
|
||||
session.Flush();
|
||||
session.Close();
|
||||
|
||||
Assert.That(foo, Is.Not.EqualTo(0));
|
||||
|
||||
sessionFactory.Close();
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SqlServerSchemaShouldBeGeneratedAndUsable() {
|
||||
var databasePath = Path.Combine(_tempDataFolder, "Orchard.mdf");
|
||||
CreateSqlServerDatabase(databasePath);
|
||||
|
||||
var recordDescriptors = new[] {
|
||||
new RecordDescriptor {Prefix = "Hello", Type = typeof (Foo)}
|
||||
};
|
||||
|
||||
var manager = (ISessionFactoryBuilder)new SessionFactoryBuilder();
|
||||
var sessionFactory = manager.BuildSessionFactory(new SessionFactoryParameters {
|
||||
Provider = "SQLite",
|
||||
DataFolder = _tempDataFolder,
|
||||
ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;",
|
||||
UpdateSchema = true,
|
||||
RecordDescriptors = recordDescriptors,
|
||||
});
|
||||
|
||||
|
||||
|
||||
var session = sessionFactory.OpenSession();
|
||||
var foo = new Foo { Name = "hi there" };
|
||||
session.Save(foo);
|
||||
session.Flush();
|
||||
session.Close();
|
||||
|
||||
Assert.That(foo, Is.Not.EqualTo(0));
|
||||
|
||||
sessionFactory.Close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,136 +0,0 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Data.Migrations;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Tests.Records;
|
||||
|
||||
namespace Orchard.Tests.Data.Migrations {
|
||||
[TestFixture]
|
||||
public class DatabaseMigrationManagerTests {
|
||||
private string _tempDataFolder;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var tempFilePath = Path.GetTempFileName();
|
||||
File.Delete(tempFilePath);
|
||||
Directory.CreateDirectory(tempFilePath);
|
||||
_tempDataFolder = tempFilePath;
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Term() {
|
||||
try { Directory.Delete(_tempDataFolder, true); }
|
||||
catch (IOException) { }
|
||||
}
|
||||
|
||||
private static void CreateSqlServerDatabase(string databasePath) {
|
||||
var databaseName = Path.GetFileNameWithoutExtension(databasePath);
|
||||
using (var connection = new SqlConnection(
|
||||
"Data Source=.\\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=true;User Instance=True;")) {
|
||||
connection.Open();
|
||||
using (var command = connection.CreateCommand()) {
|
||||
command.CommandText =
|
||||
"CREATE DATABASE " + databaseName +
|
||||
" ON PRIMARY (NAME=" + databaseName +
|
||||
", FILENAME='" + databasePath.Replace("'", "''") + "')";
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
command.CommandText =
|
||||
"EXEC sp_detach_db '" + databaseName + "', 'true'";
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MigrationManagerShouldCreateEmptySQLiteDatabaseAtGivenLocation() {
|
||||
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SQLite", _tempDataFolder, "");
|
||||
|
||||
coordinator.CreateDatabase();
|
||||
|
||||
Assert.That(File.Exists(Path.Combine(_tempDataFolder, "Orchard.db")), Is.True);
|
||||
}
|
||||
|
||||
[Test, ExpectedException(typeof(NotImplementedException))]
|
||||
public void MigrationManagerShouldNotImplementTheCreationOfSqlServer() {
|
||||
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "");
|
||||
|
||||
coordinator.CreateDatabase();
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanConnectShouldBeFalseWhenSqlServerIsInvalid() {
|
||||
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "Data Source=.\\SQLEXPRESS;Initial Catalog=Hello");
|
||||
Assert.That(coordinator.CanConnect(), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanConnectShouldBeTrueWhenValidSqlServerMdfIsTargetted() {
|
||||
var databasePath = Path.Combine(_tempDataFolder, "Orchard.mdf");
|
||||
CreateSqlServerDatabase(databasePath);
|
||||
|
||||
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;");
|
||||
Assert.That(coordinator.CanConnect(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SQLiteSchemaShouldBeGeneratedAndUsable() {
|
||||
var manager = (IDatabaseMigrationManager) new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SQLite", _tempDataFolder, "");
|
||||
|
||||
var recordDescriptors = new[] {
|
||||
new RecordDescriptor {Prefix = "Hello", Type = typeof (Foo)}
|
||||
};
|
||||
|
||||
coordinator.UpdateSchema(recordDescriptors);
|
||||
|
||||
var sessionFactory = coordinator.BuildSessionFactory(recordDescriptors);
|
||||
|
||||
var session = sessionFactory.OpenSession();
|
||||
var foo = new Foo {Name = "hi there"};
|
||||
session.Save(foo);
|
||||
session.Flush();
|
||||
session.Close();
|
||||
|
||||
Assert.That(foo, Is.Not.EqualTo(0));
|
||||
|
||||
sessionFactory.Close();
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SqlServerSchemaShouldBeGeneratedAndUsable() {
|
||||
var databasePath = Path.Combine(_tempDataFolder, "Orchard.mdf");
|
||||
CreateSqlServerDatabase(databasePath);
|
||||
|
||||
var manager = (IDatabaseMigrationManager)new DatabaseMigrationManager();
|
||||
var coordinator = manager.CreateCoordinator("SqlServer", _tempDataFolder, "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;");
|
||||
|
||||
var recordDescriptors = new[] {
|
||||
new RecordDescriptor {Prefix = "Hello", Type = typeof (Foo)}
|
||||
};
|
||||
|
||||
coordinator.UpdateSchema(recordDescriptors);
|
||||
|
||||
var sessionFactory = coordinator.BuildSessionFactory(recordDescriptors);
|
||||
|
||||
var session = sessionFactory.OpenSession();
|
||||
var foo = new Foo { Name = "hi there" };
|
||||
session.Save(foo);
|
||||
session.Flush();
|
||||
session.Close();
|
||||
|
||||
Assert.That(foo, Is.Not.EqualTo(0));
|
||||
|
||||
sessionFactory.Close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,6 +9,7 @@ using FluentNHibernate.Cfg.Db;
|
||||
using NHibernate;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Orchard.Data;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Tests {
|
||||
@@ -18,7 +19,7 @@ namespace Orchard.Tests {
|
||||
//var persistenceModel = AutoMap.Source(new Types(types))
|
||||
// .Alterations(alt => AddAlterations(alt, types))
|
||||
// .Conventions.AddFromAssemblyOf<DataModule>();
|
||||
var persistenceModel = HackSessionLocator.CreatePersistenceModel(types.Select(t => new RecordDescriptor { Prefix = "Test", Type = t }));
|
||||
var persistenceModel = AbstractBuilder.CreatePersistenceModel(types.Select(t => new RecordDescriptor { Prefix = "Test", Type = t }));
|
||||
|
||||
return Fluently.Configure()
|
||||
.Database(SQLiteConfiguration.Standard.UsingFile(fileName).ShowSql())
|
||||
|
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Tests.Environment.Configuration {
|
||||
[TestFixture]
|
||||
public class AppDataFolderTests {
|
||||
private string _tempFolder;
|
||||
private IAppDataFolder _appDataFolder;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_tempFolder = Path.GetTempFileName();
|
||||
File.Delete(_tempFolder);
|
||||
Directory.CreateDirectory(Path.Combine(_tempFolder, "alpha"));
|
||||
File.WriteAllText(Path.Combine(_tempFolder, "alpha\\beta.txt"), "beta-content");
|
||||
File.WriteAllText(Path.Combine(_tempFolder, "alpha\\gamma.txt"), "gamma-content");
|
||||
|
||||
_appDataFolder = new AppDataFolder();
|
||||
_appDataFolder.SetBasePath(_tempFolder);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Term() {
|
||||
Directory.Delete(_tempFolder, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ListFilesShouldContainSubPathAndFileName() {
|
||||
var files = _appDataFolder.ListFiles("alpha");
|
||||
Assert.That(files.Count(), Is.EqualTo(2));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha\\beta.txt"));
|
||||
Assert.That(files, Has.Some.EqualTo("alpha\\gamma.txt"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonExistantFolderShouldListAsEmptyCollection() {
|
||||
var files = _appDataFolder.ListFiles("delta");
|
||||
Assert.That(files.Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PhysicalPathAddsToBasePathAndDoesNotNeedToExist() {
|
||||
var physicalPath = _appDataFolder.MapPath("delta\\epsilon.txt");
|
||||
Assert.That(physicalPath, Is.EqualTo(Path.Combine(_tempFolder, "delta\\epsilon.txt")));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -23,7 +23,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test, Ignore("Can't be made to work until module settings and infrastructres implemented")]
|
||||
public void FactoryShouldCreateContainerThatProvidesShell() {
|
||||
|
||||
var factory = new SafeModeShellContainerFactory(_hostContainer);
|
||||
@@ -33,7 +33,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
||||
Assert.That(shell, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test, Ignore("Can't be made to work until module settings and infrastructres implemented")]
|
||||
public void ShellContainerShouldProvideLayoutViewEngine() {
|
||||
var factory = new SafeModeShellContainerFactory(_hostContainer);
|
||||
var shellContainer = factory.CreateContainer(null);
|
||||
|
@@ -135,9 +135,10 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DataUtility.cs" />
|
||||
<Compile Include="Data\Migrations\DatabaseMigrationManagerTests.cs" />
|
||||
<Compile Include="Data\Builders\SessionFactoryBuilderTests.cs" />
|
||||
<Compile Include="Data\RepositoryTests.cs" />
|
||||
<Compile Include="Data\StubLocator.cs" />
|
||||
<Compile Include="Environment\Configuration\AppDataFolderTests.cs" />
|
||||
<Compile Include="Environment\DefaultCompositionStrategyTests.cs" />
|
||||
<Compile Include="Environment\DefaultOrchardHostTests.cs" />
|
||||
<Compile Include="Environment\DefaultOrchardShellTests.cs" />
|
||||
|
@@ -13,6 +13,12 @@
|
||||
<add name="WebPageTrace"/>
|
||||
</listeners>
|
||||
</source>
|
||||
<source name="Orchard.Data.SessionLocator" switchValue="Information">
|
||||
<listeners>
|
||||
<add name="OrchardDebugTextLog" />
|
||||
<add name="WebPageTrace"/>
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<sharedListeners>
|
||||
<add name="OrchardDebugTextLog" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\logs\orchard-debug.txt" />
|
||||
|
@@ -36,6 +36,14 @@ namespace Orchard.Web {
|
||||
//TODO: what's the failed initialization story - IoC failure in app start can leave you with a zombie appdomain
|
||||
}
|
||||
|
||||
protected void Application_BeginRequest() {
|
||||
_host.BeginRequest();
|
||||
}
|
||||
|
||||
protected void Application_EndRequest() {
|
||||
_host.EndRequest();
|
||||
}
|
||||
|
||||
private void CheckMvcVersion(Version requiredVersion) {
|
||||
Assembly loadedMvcAssembly = typeof(System.Web.Mvc.Controller).Assembly;
|
||||
Version loadedMvcVersion = ReadAssemblyFileVersion(loadedMvcAssembly);
|
||||
@@ -81,9 +89,6 @@ namespace Orchard.Web {
|
||||
return new Version(attribute.Version);
|
||||
}
|
||||
|
||||
protected void Application_EndRequest() {
|
||||
_host.EndRequest();
|
||||
}
|
||||
|
||||
protected void MvcSingletons(ContainerBuilder builder) {
|
||||
builder.Register(ControllerBuilder.Current);
|
||||
|
@@ -7,7 +7,7 @@ using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Navigation.Models;
|
||||
using Orchard.Core.Settings.Models;
|
||||
using Orchard.Data;
|
||||
using Orchard.Data.Migrations;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Security;
|
||||
@@ -20,19 +20,19 @@ using MenuItem=Orchard.Core.Navigation.Models.MenuItem;
|
||||
namespace Orchard.Setup.Controllers {
|
||||
public class SetupController : Controller {
|
||||
private readonly INotifier _notifier;
|
||||
private readonly IDatabaseMigrationManager _databaseMigrationManager;
|
||||
private readonly IOrchardHost _orchardHost;
|
||||
private readonly IShellSettingsLoader _shellSettingsLoader;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
|
||||
public SetupController(
|
||||
INotifier notifier,
|
||||
IDatabaseMigrationManager databaseMigrationManager,
|
||||
IOrchardHost orchardHost,
|
||||
IShellSettingsLoader shellSettingsLoader) {
|
||||
IOrchardHost orchardHost,
|
||||
IShellSettingsLoader shellSettingsLoader,
|
||||
IAppDataFolder appDataFolder) {
|
||||
_notifier = notifier;
|
||||
_databaseMigrationManager = databaseMigrationManager;
|
||||
_orchardHost = orchardHost;
|
||||
_shellSettingsLoader = shellSettingsLoader;
|
||||
_appDataFolder = appDataFolder;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Orchard.Setup.Controllers {
|
||||
|
||||
public ActionResult Index(SetupViewModel model) {
|
||||
string message = "";
|
||||
if(!CanWriteTo(Server.MapPath("~/App_Data"), out message)) {
|
||||
if (!CanWriteTo(out message)) {
|
||||
_notifier.Error(
|
||||
T(
|
||||
"Hey, it looks like I can't write to the App_Data folder in the root of this application and that's where I need to save some of the information you're about to enter.\r\n\r\nPlease give me (the machine account this application is running under) write access to App_Data so I can get this app all set up for you.\r\n\r\nThanks!\r\n\r\n----\r\n{0}",
|
||||
@@ -62,23 +62,20 @@ namespace Orchard.Setup.Controllers {
|
||||
|
||||
try {
|
||||
var shellSettings = new ShellSettings {
|
||||
Name = "default",
|
||||
DataProvider = model.DatabaseOptions ? "SQLite" : "SqlServer",
|
||||
DataConnectionString = model.DatabaseConnectionString
|
||||
};
|
||||
|
||||
// initialize the database:
|
||||
// provider: SqlServer or SQLite
|
||||
// dataFolder: physical path (map before calling). Builtin database will be created in this location
|
||||
// connectionString: optional - if provided the dataFolder is essentially ignored, but should still be passed in
|
||||
_databaseMigrationManager.CreateCoordinator(shellSettings.DataProvider, Server.MapPath("~/App_Data"), shellSettings.DataConnectionString);
|
||||
Name = "default",
|
||||
DataProvider = model.DatabaseOptions ? "SQLite" : "SqlServer",
|
||||
DataConnectionString = model.DatabaseConnectionString
|
||||
};
|
||||
|
||||
// creating a standalone environment.
|
||||
// in theory this environment can be used to resolve any normal components by interface, and those
|
||||
// components will exist entirely in isolation - no crossover between the safemode container currently in effect
|
||||
using (var finiteEnvironment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
|
||||
try {
|
||||
var contentManager = finiteEnvironment.Resolve<IContentManager>();
|
||||
// initialize database before the transaction is created
|
||||
var sessionFactoryHolder = finiteEnvironment.Resolve<ISessionFactoryHolder>();
|
||||
sessionFactoryHolder.UpdateSchema();
|
||||
|
||||
|
||||
// create superuser
|
||||
var membershipService = finiteEnvironment.Resolve<IMembershipService>();
|
||||
@@ -87,6 +84,7 @@ namespace Orchard.Setup.Controllers {
|
||||
String.Empty, String.Empty, String.Empty,
|
||||
true));
|
||||
|
||||
|
||||
// set site name and settings
|
||||
var siteService = finiteEnvironment.Resolve<ISiteService>();
|
||||
var siteSettings = siteService.GetSiteSettings().As<SiteSettings>();
|
||||
@@ -95,6 +93,9 @@ namespace Orchard.Setup.Controllers {
|
||||
siteSettings.Record.SuperUser = model.AdminUsername;
|
||||
siteSettings.Record.PageTitleSeparator = " - ";
|
||||
|
||||
|
||||
var contentManager = finiteEnvironment.Resolve<IContentManager>();
|
||||
|
||||
// create home page as a CMS page
|
||||
var page = contentManager.Create("page");
|
||||
page.As<BodyAspect>().Text = "Welcome to Orchard";
|
||||
@@ -106,11 +107,9 @@ namespace Orchard.Setup.Controllers {
|
||||
siteSettings.Record.HomePage = "PagesHomePageProvider;" + page.Id;
|
||||
|
||||
// add a menu item for the shiny new home page
|
||||
var homeMenuItem = contentManager.Create("menuitem");
|
||||
homeMenuItem.As<MenuPart>().MenuPosition = "1";
|
||||
homeMenuItem.As<MenuPart>().MenuText = T("Home").ToString();
|
||||
homeMenuItem.As<MenuPart>().OnMainMenu = true;
|
||||
homeMenuItem.As<MenuItem>().Url = Request.Url.AbsolutePath;
|
||||
page.As<MenuPart>().MenuPosition = "1";
|
||||
page.As<MenuPart>().MenuText = T("Home").ToString();
|
||||
page.As<MenuPart>().OnMainMenu = true;
|
||||
|
||||
// add a menu item for the admin
|
||||
var adminMenuItem = contentManager.Create("menuitem");
|
||||
@@ -123,6 +122,7 @@ namespace Orchard.Setup.Controllers {
|
||||
|
||||
var authenticationService = finiteEnvironment.Resolve<IAuthenticationService>();
|
||||
authenticationService.SignIn(user, true);
|
||||
|
||||
}
|
||||
catch {
|
||||
finiteEnvironment.Resolve<ITransactionManager>().Cancel();
|
||||
@@ -145,17 +145,15 @@ namespace Orchard.Setup.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanWriteTo(string path, out string message) {
|
||||
bool CanWriteTo(out string message) {
|
||||
try {
|
||||
var systemCheckPath = Path.Combine(path, "_systemcheck.txt");
|
||||
|
||||
System.IO.File.WriteAllText(systemCheckPath, "Communicator check one two one two");
|
||||
System.IO.File.AppendAllText(systemCheckPath, "\r\nThis is Bones McCoy on a line to Sulu");
|
||||
System.IO.File.Delete(systemCheckPath);
|
||||
_appDataFolder.CreateFile("_systemcheck.txt", "Communicator check one two one two");
|
||||
_appDataFolder.DeleteFile("_systemcheck.txt");
|
||||
|
||||
message = "";
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
message = ex.Message.Replace("_systemcheck.txt", "");
|
||||
return false;
|
||||
}
|
||||
|
65
src/Orchard/Data/Builders/AbstractBuilder.cs
Normal file
65
src/Orchard/Data/Builders/AbstractBuilder.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentNHibernate.Automapping;
|
||||
using FluentNHibernate.Automapping.Alterations;
|
||||
using FluentNHibernate.Cfg;
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
using FluentNHibernate.Conventions.Helpers;
|
||||
using NHibernate;
|
||||
using NHibernate.Cfg;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Data.Builders {
|
||||
public abstract class AbstractBuilder {
|
||||
protected abstract IPersistenceConfigurer GetPersistenceConfigurer();
|
||||
|
||||
public ISessionFactory BuildSessionFactory(SessionFactoryParameters parameters) {
|
||||
var database = GetPersistenceConfigurer();
|
||||
var persistenceModel = CreatePersistenceModel(parameters.RecordDescriptors);
|
||||
|
||||
var sessionFactory = Fluently.Configure()
|
||||
.Database(database)
|
||||
.Mappings(m => m.AutoMappings.Add(persistenceModel))
|
||||
.ExposeConfiguration(config => Initialization(parameters, config))
|
||||
.BuildSessionFactory();
|
||||
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
private static void Initialization(SessionFactoryParameters parameters, Configuration configuration) {
|
||||
if (parameters.UpdateSchema) {
|
||||
var update = new SchemaUpdate(configuration);
|
||||
update.Execute(false/*script*/, true /*doUpdate*/);
|
||||
}
|
||||
}
|
||||
|
||||
public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
return AutoMap.Source(new TypeSource(recordDescriptors))
|
||||
// Ensure that namespaces of types are never auto-imported, so that
|
||||
// identical type names from different namespaces can be mapped without ambiguity
|
||||
.Conventions.Setup(x => x.Add(AutoImport.Never()))
|
||||
.Conventions.Add(new RecordTableNameConvention(recordDescriptors))
|
||||
.Alterations(alt => {
|
||||
foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) {
|
||||
alt.Add(new AutoMappingOverrideAlteration(recordAssembly));
|
||||
}
|
||||
alt.AddFromAssemblyOf<DataModule>();
|
||||
alt.Add(new ContentItemAlteration(recordDescriptors));
|
||||
})
|
||||
.Conventions.AddFromAssemblyOf<DataModule>();
|
||||
}
|
||||
|
||||
class TypeSource : ITypeSource {
|
||||
private readonly IEnumerable<RecordDescriptor> _recordDescriptors;
|
||||
|
||||
public TypeSource(IEnumerable<RecordDescriptor> recordDescriptors) { _recordDescriptors = recordDescriptors; }
|
||||
|
||||
public IEnumerable<Type> GetTypes() { return _recordDescriptors.Select(descriptor => descriptor.Type); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
19
src/Orchard/Data/Builders/ISessionFactoryBuilder.cs
Normal file
19
src/Orchard/Data/Builders/ISessionFactoryBuilder.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using NHibernate;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Data.Builders {
|
||||
|
||||
public interface ISessionFactoryBuilder : IDependency {
|
||||
ISessionFactory BuildSessionFactory(SessionFactoryParameters sessionFactoryParameters);
|
||||
}
|
||||
|
||||
public class SessionFactoryParameters {
|
||||
public IEnumerable<RecordDescriptor> RecordDescriptors { get; set; }
|
||||
public bool UpdateSchema { get; set; }
|
||||
|
||||
public string Provider { get; set; }
|
||||
public string DataFolder { get; set; }
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
}
|
@@ -1,12 +1,12 @@
|
||||
using System.IO;
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
|
||||
namespace Orchard.Data.Migrations {
|
||||
public class SQLiteDatabaseCoordinator : DatabaseCoordinatorBase {
|
||||
namespace Orchard.Data.Builders {
|
||||
public class SQLiteBuilder : AbstractBuilder {
|
||||
private readonly string _dataFolder;
|
||||
private readonly string _connectionString;
|
||||
|
||||
public SQLiteDatabaseCoordinator(string dataFolder, string connectionString) {
|
||||
public SQLiteBuilder(string dataFolder, string connectionString) {
|
||||
_dataFolder = dataFolder;
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
@@ -14,6 +14,10 @@ namespace Orchard.Data.Migrations {
|
||||
protected override IPersistenceConfigurer GetPersistenceConfigurer() {
|
||||
var persistence = SQLiteConfiguration.Standard;
|
||||
if (string.IsNullOrEmpty(_connectionString)) {
|
||||
|
||||
if (!Directory.Exists(_dataFolder))
|
||||
Directory.CreateDirectory(_dataFolder);
|
||||
|
||||
persistence = persistence.UsingFile(Path.Combine(_dataFolder, "Orchard.db"));
|
||||
}
|
||||
else {
|
17
src/Orchard/Data/Builders/SessionFactoryBuilder.cs
Normal file
17
src/Orchard/Data/Builders/SessionFactoryBuilder.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using NHibernate;
|
||||
|
||||
namespace Orchard.Data.Builders {
|
||||
public class SessionFactoryBuilder : ISessionFactoryBuilder {
|
||||
public ISessionFactory BuildSessionFactory(SessionFactoryParameters sessionFactoryParameters) {
|
||||
AbstractBuilder builder;
|
||||
if (string.Equals(sessionFactoryParameters.Provider, "SQLite", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
builder = new SQLiteBuilder(sessionFactoryParameters.DataFolder, sessionFactoryParameters.ConnectionString);
|
||||
}
|
||||
else {
|
||||
builder = new SqlServerBuilder(sessionFactoryParameters.DataFolder, sessionFactoryParameters.ConnectionString);
|
||||
}
|
||||
return builder.BuildSessionFactory(sessionFactoryParameters);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
|
||||
namespace Orchard.Data.Migrations {
|
||||
public class SqlServerDatabaseCoordinator : DatabaseCoordinatorBase {
|
||||
namespace Orchard.Data.Builders {
|
||||
public class SqlServerBuilder : AbstractBuilder {
|
||||
private readonly string _dataFolder;
|
||||
private readonly string _connectionString;
|
||||
|
||||
public SqlServerDatabaseCoordinator(string dataFolder, string connectionString) {
|
||||
public SqlServerBuilder(string dataFolder, string connectionString) {
|
||||
_dataFolder = dataFolder;
|
||||
_connectionString = connectionString;
|
||||
}
|
@@ -4,7 +4,6 @@ namespace Orchard.Data {
|
||||
public class DataModule : Module {
|
||||
protected override void Load(ContainerBuilder builder) {
|
||||
builder.RegisterGeneric(typeof (Repository<>)).As(typeof (IRepository<>)).FactoryScoped();
|
||||
builder.Register<HackSessionLocator>().As<ISessionLocator>().ContainerScoped();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,97 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web.Hosting;
|
||||
using FluentNHibernate.Automapping;
|
||||
using FluentNHibernate.Automapping.Alterations;
|
||||
using FluentNHibernate.Cfg;
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
using FluentNHibernate.Conventions.Helpers;
|
||||
using NHibernate;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Orchard.Data.Conventions;
|
||||
using Orchard.Environment;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class HackSessionLocator : ISessionLocator, IDisposable {
|
||||
private readonly ICompositionStrategy _compositionStrategy;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
private static ISessionFactory _sessionFactory;
|
||||
private ISession _session;
|
||||
|
||||
public HackSessionLocator(ICompositionStrategy compositionStrategy, ITransactionManager transactionManager) {
|
||||
_compositionStrategy = compositionStrategy;
|
||||
_transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
private ISessionFactory BindSessionFactory() {
|
||||
// TEMP: a real scenario would call for a session factory locator
|
||||
// that would eventually imply the need for configuration against one or more actual sources
|
||||
// and a means to enlist record types from active modules into correct session factory
|
||||
|
||||
var hackPath = HostingEnvironment.MapPath("~/App_Data/hack.db");
|
||||
|
||||
var database = SQLiteConfiguration.Standard.UsingFile(hackPath);
|
||||
|
||||
var recordDescriptors = _compositionStrategy.GetRecordDescriptors();
|
||||
|
||||
return _sessionFactory ??
|
||||
Interlocked.CompareExchange(
|
||||
ref _sessionFactory,
|
||||
BuildSessionFactory(database, recordDescriptors), null) ?? _sessionFactory;
|
||||
|
||||
}
|
||||
|
||||
private static ISessionFactory BuildSessionFactory(IPersistenceConfigurer database, IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
return Fluently.Configure()
|
||||
.Database(database)
|
||||
.Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors)))
|
||||
.ExposeConfiguration(c => new SchemaUpdate(c).Execute(false /*script*/, true /*doUpdate*/))
|
||||
.BuildSessionFactory();
|
||||
}
|
||||
|
||||
public static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
var types = recordDescriptors.Select(d => d.Type);
|
||||
return AutoMap.Source(new TypeSource(types))
|
||||
// Ensure that namespaces of types are never auto-imported, so that
|
||||
// identical type names from different namespaces can be mapped without ambiguity
|
||||
.Conventions.Setup(x => x.Add(AutoImport.Never()))
|
||||
.Conventions.Add(new RecordTableNameConvention(recordDescriptors))
|
||||
.Alterations(alt => {
|
||||
foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) {
|
||||
alt.Add(new AutoMappingOverrideAlteration(recordAssembly));
|
||||
}
|
||||
alt.AddFromAssemblyOf<DataModule>();
|
||||
alt.Add(new ContentItemAlteration(recordDescriptors));
|
||||
})
|
||||
.Conventions.AddFromAssemblyOf<DataModule>();
|
||||
}
|
||||
|
||||
private class TypeSource : ITypeSource {
|
||||
private readonly IEnumerable<Type> _recordTypes;
|
||||
|
||||
public TypeSource(IEnumerable<Type> recordTypes) {
|
||||
_recordTypes = recordTypes;
|
||||
}
|
||||
|
||||
public IEnumerable<Type> GetTypes() {
|
||||
return _recordTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public ISession For(Type entityType) {
|
||||
var sessionFactory = BindSessionFactory();
|
||||
_transactionManager.Demand();
|
||||
return _session ?? Interlocked.CompareExchange(ref _session, sessionFactory.OpenSession(), null) ?? _session;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
//if (_session != null) {
|
||||
// //_session.Flush();
|
||||
// _session.Close();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,7 +2,7 @@ using System;
|
||||
using NHibernate;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public interface ISessionLocator {
|
||||
public interface ISessionLocator : IDependency {
|
||||
ISession For(Type entityType);
|
||||
}
|
||||
}
|
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentNHibernate.Automapping;
|
||||
using FluentNHibernate.Automapping.Alterations;
|
||||
using FluentNHibernate.Cfg;
|
||||
using FluentNHibernate.Cfg.Db;
|
||||
using FluentNHibernate.Conventions.Helpers;
|
||||
using NHibernate;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Data.Migrations {
|
||||
public abstract class DatabaseCoordinatorBase : IDatabaseCoordinator {
|
||||
protected abstract IPersistenceConfigurer GetPersistenceConfigurer();
|
||||
|
||||
public virtual bool CanConnect() {
|
||||
try {
|
||||
var sessionFactory = Fluently.Configure()
|
||||
.Database(GetPersistenceConfigurer())
|
||||
.BuildSessionFactory();
|
||||
try {
|
||||
// attempting to open a session validates a connection can be made
|
||||
var session = sessionFactory.OpenSession();
|
||||
session.Close();
|
||||
}
|
||||
finally {
|
||||
sessionFactory.Close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CreateDatabase() {
|
||||
// creating a session factory appears to be sufficient for causing a database file to be created for inplace providers
|
||||
var sessionFactory = Fluently.Configure()
|
||||
.Database(GetPersistenceConfigurer())
|
||||
.BuildSessionFactory();
|
||||
sessionFactory.Close();
|
||||
}
|
||||
|
||||
public void UpdateSchema(IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
var configuration = Fluently.Configure()
|
||||
.Database(GetPersistenceConfigurer())
|
||||
.Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors)))
|
||||
.BuildConfiguration();
|
||||
|
||||
var updater = new SchemaUpdate(configuration);
|
||||
updater.Execute(true /*script*/, true /*doUpdate*/);
|
||||
}
|
||||
|
||||
public ISessionFactory BuildSessionFactory(IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
return Fluently.Configure()
|
||||
.Database(GetPersistenceConfigurer())
|
||||
.Mappings(m => m.AutoMappings.Add(CreatePersistenceModel(recordDescriptors)))
|
||||
.BuildSessionFactory();
|
||||
}
|
||||
|
||||
static AutoPersistenceModel CreatePersistenceModel(IEnumerable<RecordDescriptor> recordDescriptors) {
|
||||
return AutoMap.Source(new TypeSource(recordDescriptors))
|
||||
// Ensure that namespaces of types are never auto-imported, so that
|
||||
// identical type names from different namespaces can be mapped without ambiguity
|
||||
.Conventions.Setup(x => x.Add(AutoImport.Never()))
|
||||
.Conventions.Add(new RecordTableNameConvention(recordDescriptors))
|
||||
.Alterations(alt => {
|
||||
foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) {
|
||||
alt.Add(new AutoMappingOverrideAlteration(recordAssembly));
|
||||
}
|
||||
alt.AddFromAssemblyOf<DataModule>();
|
||||
alt.Add(new ContentItemAlteration(recordDescriptors));
|
||||
})
|
||||
.Conventions.AddFromAssemblyOf<DataModule>();
|
||||
}
|
||||
|
||||
class TypeSource : ITypeSource {
|
||||
private readonly IEnumerable<RecordDescriptor> _recordDescriptors;
|
||||
|
||||
public TypeSource(IEnumerable<RecordDescriptor> recordDescriptors) { _recordDescriptors = recordDescriptors; }
|
||||
|
||||
public IEnumerable<Type> GetTypes() { return _recordDescriptors.Select(descriptor => descriptor.Type); }
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Data.Migrations {
|
||||
public class DatabaseMigrationManager : IDatabaseMigrationManager {
|
||||
public IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString) {
|
||||
if (string.Equals(provider, "SQLite", StringComparison.InvariantCultureIgnoreCase))
|
||||
return new SQLiteDatabaseCoordinator(dataFolder, connectionString);
|
||||
return new SqlServerDatabaseCoordinator(dataFolder, connectionString);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NHibernate;
|
||||
using Orchard.Environment;
|
||||
|
||||
namespace Orchard.Data.Migrations {
|
||||
public interface IDatabaseCoordinator {
|
||||
bool CanConnect();
|
||||
void CreateDatabase();
|
||||
|
||||
/// <summary>
|
||||
/// Should only be called in a development or evaluation environment. Automatic schema migration
|
||||
/// not a really safe practice on production data sources.
|
||||
/// </summary>
|
||||
/// <param name="recordDescriptors">Set of known records to be applied</param>
|
||||
void UpdateSchema(IEnumerable<RecordDescriptor> recordDescriptors);
|
||||
|
||||
ISessionFactory BuildSessionFactory(IEnumerable<RecordDescriptor> recordDescriptors);
|
||||
}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
namespace Orchard.Data.Migrations {
|
||||
public interface IDatabaseMigrationManager {
|
||||
IDatabaseCoordinator CreateCoordinator(string provider, string dataFolder, string connectionString);
|
||||
}
|
||||
}
|
75
src/Orchard/Data/SessionFactoryHolder.cs
Normal file
75
src/Orchard/Data/SessionFactoryHolder.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.IO;
|
||||
using NHibernate;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public interface ISessionFactoryHolder : ISingletonDependency {
|
||||
ISessionFactory GetSessionFactory();
|
||||
void UpdateSchema();
|
||||
}
|
||||
|
||||
public class SessionFactoryHolder : ISessionFactoryHolder {
|
||||
private readonly IShellSettings _shellSettings;
|
||||
private readonly ICompositionStrategy _compositionStrategy;
|
||||
private readonly ISessionFactoryBuilder _sessionFactoryBuilder;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
|
||||
private ISessionFactory _sessionFactory;
|
||||
|
||||
public SessionFactoryHolder(
|
||||
IShellSettings shellSettings,
|
||||
ICompositionStrategy compositionStrategy,
|
||||
ISessionFactoryBuilder sessionFactoryBuilder,
|
||||
IAppDataFolder appDataFolder) {
|
||||
_shellSettings = shellSettings;
|
||||
_compositionStrategy = compositionStrategy;
|
||||
_sessionFactoryBuilder = sessionFactoryBuilder;
|
||||
_appDataFolder = appDataFolder;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void UpdateSchema() {
|
||||
lock (this) {
|
||||
if (_sessionFactory != null) {
|
||||
Logger.Error("UpdateSchema can not be called after a session factory was created");
|
||||
throw new OrchardException("UpdateSchema can not be called after a session factory was created");
|
||||
}
|
||||
|
||||
_sessionFactory = BuildSessionFactory(true);
|
||||
}
|
||||
}
|
||||
|
||||
public ISessionFactory GetSessionFactory() {
|
||||
lock (this) {
|
||||
if (_sessionFactory == null) {
|
||||
_sessionFactory = BuildSessionFactory(false);
|
||||
}
|
||||
}
|
||||
return _sessionFactory;
|
||||
}
|
||||
|
||||
private ISessionFactory BuildSessionFactory(bool updateSchema) {
|
||||
Logger.Debug("Building session factory");
|
||||
|
||||
var shellPath = _appDataFolder.CreateDirectory(Path.Combine("Sites", _shellSettings.Name));
|
||||
|
||||
var sessionFactory = _sessionFactoryBuilder.BuildSessionFactory(new SessionFactoryParameters {
|
||||
Provider = _shellSettings.DataProvider,
|
||||
DataFolder = shellPath,
|
||||
ConnectionString = _shellSettings.DataConnectionString,
|
||||
UpdateSchema = updateSchema,
|
||||
RecordDescriptors = _compositionStrategy.GetRecordDescriptors(),
|
||||
});
|
||||
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
38
src/Orchard/Data/SessionLocator.cs
Normal file
38
src/Orchard/Data/SessionLocator.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using NHibernate;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class SessionLocator : ISessionLocator {
|
||||
private readonly ISessionFactoryHolder _sessionFactoryHolder;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
private ISession _session;
|
||||
|
||||
public SessionLocator(
|
||||
ISessionFactoryHolder sessionFactoryHolder,
|
||||
ITransactionManager transactionManager) {
|
||||
_sessionFactoryHolder = sessionFactoryHolder;
|
||||
_transactionManager = transactionManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
|
||||
public ISession For(Type entityType) {
|
||||
Logger.Debug("Acquiring session for {0}", entityType);
|
||||
|
||||
if (_session == null) {
|
||||
|
||||
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
|
||||
|
||||
_transactionManager.Demand();
|
||||
|
||||
Logger.Information("Openning database session");
|
||||
_session = sessionFactory.OpenSession();
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
74
src/Orchard/Environment/Configuration/AppDataFolder.cs
Normal file
74
src/Orchard/Environment/Configuration/AppDataFolder.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Hosting;
|
||||
|
||||
namespace Orchard.Environment.Configuration {
|
||||
/// <summary>
|
||||
/// Abstraction of App_Data folder
|
||||
/// Expected to work on physical filesystem, but decouples core
|
||||
/// system from web hosting apis
|
||||
/// </summary>
|
||||
public interface IAppDataFolder {
|
||||
IEnumerable<string> ListFiles(string path);
|
||||
|
||||
void CreateFile(string path, string content);
|
||||
void DeleteFile(string path);
|
||||
|
||||
string CreateDirectory(string path);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// May be called to initialize component when not in a hosting environment
|
||||
/// app domain
|
||||
/// </summary>
|
||||
void SetBasePath(string basePath);
|
||||
string MapPath(string path);
|
||||
|
||||
}
|
||||
|
||||
public class AppDataFolder : IAppDataFolder {
|
||||
protected string _basePath;
|
||||
|
||||
public AppDataFolder() {
|
||||
_basePath = HostingEnvironment.MapPath("~/App_Data");
|
||||
}
|
||||
|
||||
public void CreateFile(string path, string content) {
|
||||
File.WriteAllText(Path.Combine(_basePath, path), content);
|
||||
}
|
||||
|
||||
public void DeleteFile(string path) {
|
||||
File.Delete(Path.Combine(_basePath, path));
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListFiles(string path) {
|
||||
var directoryPath = Path.Combine(_basePath, path);
|
||||
if (!Directory.Exists(directoryPath))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
var files = Directory.GetFiles(directoryPath);
|
||||
|
||||
return files.Select(file => {
|
||||
var fileName = Path.GetFileName(file);
|
||||
return Path.Combine(path, fileName);
|
||||
});
|
||||
}
|
||||
|
||||
public string CreateDirectory(string path) {
|
||||
var directory = Path.Combine(_basePath, path);
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
return directory;
|
||||
}
|
||||
|
||||
public void SetBasePath(string basePath) {
|
||||
_basePath = basePath;
|
||||
}
|
||||
|
||||
public string MapPath(string path) {
|
||||
return Path.Combine(_basePath, path);
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,9 +14,11 @@ namespace Orchard.Environment.Configuration {
|
||||
}
|
||||
|
||||
public class ShellSettingsLoader : IShellSettingsLoader {
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
Localizer T { get; set; }
|
||||
|
||||
public ShellSettingsLoader() {
|
||||
public ShellSettingsLoader(IAppDataFolder appDataFolder) {
|
||||
_appDataFolder = appDataFolder;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@@ -30,31 +32,24 @@ namespace Orchard.Environment.Configuration {
|
||||
if (string.IsNullOrEmpty(settings.Name))
|
||||
throw new ArgumentException(T("Settings \"Name\" is not set.").ToString());
|
||||
|
||||
var sitesPath = HostingEnvironment.MapPath("~/App_Data/Sites");
|
||||
|
||||
if (string.IsNullOrEmpty(sitesPath))
|
||||
throw new ArgumentException(T("Can't determine the path on the server to save settings. Looking for something like \"~/App_Data/Sites\".").ToString());
|
||||
|
||||
if (!Directory.Exists(sitesPath))
|
||||
Directory.CreateDirectory(sitesPath);
|
||||
|
||||
var filePath = Path.Combine(sitesPath, string.Format("{0}.txt", settings.Name));
|
||||
File.WriteAllText(filePath, ComposeSettings(settings));
|
||||
var filePath = Path.Combine("Sites", settings.Name + ".txt");
|
||||
_appDataFolder.CreateFile(filePath, ComposeSettings(settings));
|
||||
}
|
||||
|
||||
static IEnumerable<IShellSettings> LoadSettings() {
|
||||
IEnumerable<IShellSettings> LoadSettings() {
|
||||
foreach (var yamlDocument in LoadFiles()) {
|
||||
yield return ParseSettings(yamlDocument);
|
||||
}
|
||||
}
|
||||
|
||||
static IEnumerable<YamlDocument> LoadFiles() {
|
||||
var sitesPath = HostingEnvironment.MapPath("~/App_Data/Sites");
|
||||
if (sitesPath != null && Directory.Exists(sitesPath)) {
|
||||
foreach (var settingsFilePath in Directory.GetFiles(sitesPath, "*.txt")) {
|
||||
var yamlStream = YamlParser.Load(settingsFilePath);
|
||||
yield return yamlStream.Documents.Single();
|
||||
}
|
||||
IEnumerable<YamlDocument> LoadFiles() {
|
||||
var filePaths = _appDataFolder.ListFiles("Sites")
|
||||
.Where(path => path.EndsWith(".txt", StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
foreach (var filePath in filePaths) {
|
||||
var yamlStream = YamlParser.Load(_appDataFolder.MapPath(filePath));
|
||||
yield return yamlStream.Documents.Single();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +60,10 @@ namespace Orchard.Environment.Configuration {
|
||||
.ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value);
|
||||
|
||||
return new ShellSettings {
|
||||
Name = GetValue(fields, "Name"),
|
||||
DataProvider = GetValue(fields, "DataProvider"),
|
||||
DataConnectionString = GetValue(fields, "DataConnectionString")
|
||||
};
|
||||
Name = GetValue(fields, "Name"),
|
||||
DataProvider = GetValue(fields, "DataProvider"),
|
||||
DataConnectionString = GetValue(fields, "DataConnectionString")
|
||||
};
|
||||
}
|
||||
|
||||
static string GetValue(
|
||||
|
@@ -36,16 +36,23 @@ namespace Orchard.Environment {
|
||||
get { return _current; }
|
||||
}
|
||||
|
||||
|
||||
void IOrchardHost.Initialize() {
|
||||
ViewEngines.Engines.Insert(0, LayoutViewEngine.CreateShim());
|
||||
_controllerBuilder.SetControllerFactory(new OrchardControllerFactory());
|
||||
ServiceLocator.SetLocator(t => _containerProvider.RequestContainer.Resolve(t));
|
||||
|
||||
Initialize();
|
||||
CreateAndActivateShell();
|
||||
}
|
||||
|
||||
void IOrchardHost.Reinitialize() {
|
||||
Initialize();
|
||||
_current = null;
|
||||
//CreateAndActivateShell();
|
||||
}
|
||||
|
||||
|
||||
void IOrchardHost.BeginRequest() {
|
||||
BeginRequest();
|
||||
}
|
||||
|
||||
void IOrchardHost.EndRequest() {
|
||||
@@ -57,19 +64,30 @@ namespace Orchard.Environment {
|
||||
return new StandaloneEnvironment(shellContainer);
|
||||
}
|
||||
|
||||
protected virtual void Initialize() {
|
||||
var shellContainer = CreateShellContainer();
|
||||
var shell = shellContainer.Resolve<IOrchardShell>();
|
||||
shell.Activate();
|
||||
_current = shell;
|
||||
protected virtual void CreateAndActivateShell() {
|
||||
lock (this) {
|
||||
if (_current != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire off one-time install events on an alternate container
|
||||
HackInstallSimulation();
|
||||
var shellContainer = CreateShellContainer();
|
||||
var shell = shellContainer.Resolve<IOrchardShell>();
|
||||
shell.Activate();
|
||||
_current = shell;
|
||||
|
||||
// Activate extensions inside shell container
|
||||
HackSimulateExtensionActivation(shellContainer);
|
||||
// Fire off one-time install events on an alternate container
|
||||
HackInstallSimulation();
|
||||
|
||||
// Activate extensions inside shell container
|
||||
HackSimulateExtensionActivation(shellContainer);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void BeginRequest() {
|
||||
if (_current == null) {
|
||||
CreateAndActivateShell();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void EndRequest() {
|
||||
_containerProvider.DisposeRequestContainer();
|
||||
@@ -94,8 +112,9 @@ namespace Orchard.Environment {
|
||||
private IContainer CreateShellContainer(IShellSettings shellSettings) {
|
||||
foreach (var factory in _shellContainerFactories) {
|
||||
var container = factory.CreateContainer(shellSettings);
|
||||
if (container != null)
|
||||
if (container != null) {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -7,16 +7,21 @@ namespace Orchard.Environment {
|
||||
/// </summary>
|
||||
void Initialize();
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a request ends to deterministically commit and dispose outstanding activity
|
||||
/// </summary>
|
||||
void EndRequest();
|
||||
|
||||
/// <summary>
|
||||
/// Called when configuration changes requires the shell topology to be reloaded and applied
|
||||
/// </summary>
|
||||
void Reinitialize();
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a request begins to offer a just-in-time reinitialization point
|
||||
/// </summary>
|
||||
void BeginRequest();
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a request ends to deterministically commit and dispose outstanding activity
|
||||
/// </summary>
|
||||
void EndRequest();
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to build an temporary self-contained instance of a shell's configured code.
|
||||
/// Services may be resolved from within this instance to configure and initialize it's storage.
|
||||
|
@@ -22,6 +22,7 @@ namespace Orchard.Environment {
|
||||
builder.Register<DefaultOrchardHost>().As<IOrchardHost>().SingletonScoped();
|
||||
builder.Register<DefaultCompositionStrategy>().As<ICompositionStrategy>().SingletonScoped();
|
||||
builder.Register<DefaultShellContainerFactory>().As<IShellContainerFactory>().SingletonScoped();
|
||||
builder.Register<AppDataFolder>().As<IAppDataFolder>().SingletonScoped();
|
||||
builder.Register<ShellSettingsLoader>().As<IShellSettingsLoader>().SingletonScoped();
|
||||
builder.Register<SafeModeShellContainerFactory>().As<IShellContainerFactory>().SingletonScoped();
|
||||
|
||||
|
@@ -23,6 +23,7 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
|
||||
// add module types to container being built
|
||||
var addingModulesAndServices = new ContainerBuilder();
|
||||
addingModulesAndServices.Register(settings).As<IShellSettings>();
|
||||
addingModulesAndServices.Register<DefaultOrchardShell>().As<IOrchardShell>().SingletonScoped();
|
||||
|
||||
foreach (var moduleType in _compositionStrategy.GetModuleTypes()) {
|
||||
|
@@ -8,7 +8,7 @@ using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Data.Migrations;
|
||||
using Orchard.Data.Builders;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Extensions;
|
||||
using Orchard.Localization;
|
||||
@@ -53,7 +53,7 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
builder.Register<PageClassBuilder>().As<IPageClassBuilder>().ContainerScoped();
|
||||
builder.Register<Notifier>().As<INotifier>().ContainerScoped();
|
||||
builder.Register<NotifyFilter>().As<IFilterProvider>().ContainerScoped();
|
||||
builder.Register<DatabaseMigrationManager>().As<IDatabaseMigrationManager>().ContainerScoped();
|
||||
builder.Register<SessionFactoryBuilder>().As<ISessionFactoryBuilder>().ContainerScoped();
|
||||
|
||||
// safe mode specific implementations of needed service interfaces
|
||||
builder.Register<NullHackInstallationGenerator>().As<IHackInstallationGenerator>().ContainerScoped();
|
||||
|
@@ -99,7 +99,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Data\HackSessionLocator.cs" />
|
||||
<Compile Include="Data\SessionLocator.cs" />
|
||||
<Compile Include="Data\IRepository.cs" />
|
||||
<Compile Include="Data\ISessionLocator.cs" />
|
||||
<Compile Include="Data\DataModule.cs" />
|
||||
@@ -133,12 +133,13 @@
|
||||
<Compile Include="ContentManagement\Handlers\RemoveContentContext.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\VersionContentContext.cs" />
|
||||
<Compile Include="Data\Conventions\RecordTableNameConvention.cs" />
|
||||
<Compile Include="Data\Migrations\DatabaseCoordinatorBase.cs" />
|
||||
<Compile Include="Data\Migrations\DatabaseMigrationManager.cs" />
|
||||
<Compile Include="Data\Migrations\IDatabaseCoordinator.cs" />
|
||||
<Compile Include="Data\Migrations\IDatabaseMigrationManager.cs" />
|
||||
<Compile Include="Data\Migrations\SQLiteDatabaseCoordinator.cs" />
|
||||
<Compile Include="Data\Migrations\SqlServerDatabaseCoordinator.cs" />
|
||||
<Compile Include="Data\Builders\AbstractBuilder.cs" />
|
||||
<Compile Include="Data\Builders\SessionFactoryBuilder.cs" />
|
||||
<Compile Include="Data\Builders\ISessionFactoryBuilder.cs" />
|
||||
<Compile Include="Data\Builders\SQLiteBuilder.cs" />
|
||||
<Compile Include="Data\Builders\SqlServerBuilder.cs" />
|
||||
<Compile Include="Data\SessionFactoryHolder.cs" />
|
||||
<Compile Include="Environment\Configuration\AppDataFolder.cs" />
|
||||
<Compile Include="Environment\Configuration\ShellSettingsLoader.cs" />
|
||||
<Compile Include="Environment\ExtensibleInterceptionModule.cs" />
|
||||
<Compile Include="Environment\ShellBuilders\DefaultShellContainerFactory.cs" />
|
||||
|
Reference in New Issue
Block a user