diff --git a/.gitignore b/.gitignore index 26953347..18de70f2 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,5 @@ Oqtane.Server/Data/*.db /Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml Oqtane.Server/Content Oqtane.Server/wwwroot/Packages/**/assets.json - +Oqtane.Server/wwwroot/Packages/*.log diff --git a/Oqtane.Database.SqlServer/LocalDbDatabase.cs b/Oqtane.Database.SqlServer/LocalDbDatabase.cs deleted file mode 100644 index 3e0716d3..00000000 --- a/Oqtane.Database.SqlServer/LocalDbDatabase.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Oqtane.Database.SqlServer -{ - public class LocalDbDatabase : SqlServerDatabaseBase - { - private static string _friendlyName => "Local Database"; - private static string _name => "LocalDB"; - - static LocalDbDatabase() - { - Initialize(typeof(LocalDbDatabase)); - } - - public LocalDbDatabase() :base(_name, _friendlyName) { } - } -} diff --git a/Oqtane.Database.SqlServer/SqlServerDatabase.cs b/Oqtane.Database.SqlServer/SqlServerDatabase.cs index 69d48a7d..08162320 100644 --- a/Oqtane.Database.SqlServer/SqlServerDatabase.cs +++ b/Oqtane.Database.SqlServer/SqlServerDatabase.cs @@ -1,6 +1,16 @@ +using System; +using System.Data; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Databases; +using Oqtane.Shared; + namespace Oqtane.Database.SqlServer { - public class SqlServerDatabase : SqlServerDatabaseBase + public class SqlServerDatabase : DatabaseBase { private static string _friendlyName => "SQL Server"; @@ -11,6 +21,66 @@ namespace Oqtane.Database.SqlServer Initialize(typeof(SqlServerDatabase)); } - public SqlServerDatabase() : base(_name, _friendlyName) { } + public SqlServerDatabase() : base(_name, _friendlyName) + { + } + + public override string Provider => "Microsoft.EntityFrameworkCore.SqlServer"; + + public override OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) + { + return table.Column(name: name, nullable: false).Annotation("SqlServer:Identity", "1, 1"); + } + + public override int ExecuteNonQuery(string connectionString, string query) + { + var conn = new SqlConnection(FormatConnectionString(connectionString)); + var cmd = conn.CreateCommand(); + using (conn) + { + PrepareCommand(conn, cmd, query); + var val = -1; + try + { + val = cmd.ExecuteNonQuery(); + } + catch + { + // an error occurred executing the query + } + return val; + } + + } + + public override IDataReader ExecuteReader(string connectionString, string query) + { + var conn = new SqlConnection(FormatConnectionString(connectionString)); + var cmd = conn.CreateCommand(); + PrepareCommand(conn, cmd, query); + var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); + return dr; + } + + public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) + { + return optionsBuilder.UseSqlServer(connectionString); + } + + private string FormatConnectionString(string connectionString) + { + return connectionString.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString()); + } + + private void PrepareCommand(SqlConnection conn, SqlCommand cmd, string query) + { + if (conn.State != ConnectionState.Open) + { + conn.Open(); + } + cmd.Connection = conn; + cmd.CommandText = query; + cmd.CommandType = CommandType.Text; + } } } diff --git a/Oqtane.Database.SqlServer/SqlServerDatabaseBase.cs b/Oqtane.Database.SqlServer/SqlServerDatabaseBase.cs deleted file mode 100644 index d41350d6..00000000 --- a/Oqtane.Database.SqlServer/SqlServerDatabaseBase.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Data; -using Microsoft.Data.SqlClient; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Migrations.Operations; -using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; -using Oqtane.Databases; -using Oqtane.Shared; - -namespace Oqtane.Database.SqlServer -{ - public abstract class SqlServerDatabaseBase : DatabaseBase - { - protected SqlServerDatabaseBase(string name, string friendlyName) : base(name, friendlyName) - { - } - - public override string Provider => "Microsoft.EntityFrameworkCore.SqlServer"; - - public override OperationBuilder AddAutoIncrementColumn(ColumnsBuilder table, string name) - { - return table.Column(name: name, nullable: false).Annotation("SqlServer:Identity", "1, 1"); - } - - public override int ExecuteNonQuery(string connectionString, string query) - { - var conn = new SqlConnection(FormatConnectionString(connectionString)); - var cmd = conn.CreateCommand(); - using (conn) - { - PrepareCommand(conn, cmd, query); - var val = -1; - try - { - val = cmd.ExecuteNonQuery(); - } - catch - { - // an error occurred executing the query - } - return val; - } - - } - - public override IDataReader ExecuteReader(string connectionString, string query) - { - var conn = new SqlConnection(FormatConnectionString(connectionString)); - var cmd = conn.CreateCommand(); - PrepareCommand(conn, cmd, query); - var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); - return dr; - } - - public override DbContextOptionsBuilder UseDatabase(DbContextOptionsBuilder optionsBuilder, string connectionString) - { - return optionsBuilder.UseSqlServer(connectionString); - } - - private string FormatConnectionString(string connectionString) - { - return connectionString.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString()); - } - - private void PrepareCommand(SqlConnection conn, SqlCommand cmd, string query) - { - if (conn.State != ConnectionState.Open) - { - conn.Open(); - } - cmd.Connection = conn; - cmd.CommandText = query; - cmd.CommandType = CommandType.Text; - } - } -} diff --git a/Oqtane.Server/Controllers/DatabaseController.cs b/Oqtane.Server/Controllers/DatabaseController.cs index bd3422e8..6e9f7106 100644 --- a/Oqtane.Server/Controllers/DatabaseController.cs +++ b/Oqtane.Server/Controllers/DatabaseController.cs @@ -20,7 +20,7 @@ namespace Oqtane.Controllers Name = "LocalDB", FriendlyName = "Local Database", ControlType = "Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client", - DBType = "Oqtane.Database.SqlServer.LocalDbDatabase, Oqtane.Database.SqlServer", + DBType = "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer", Package = "Oqtane.Database.SqlServer" }, new() diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 6a9ba2ba..7fa40011 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -47,9 +47,8 @@ namespace Oqtane.Infrastructure if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey))) { result.Success = true; - using (var scope = _serviceScopeFactory.CreateScope()) + using (var db = GetInstallationContext()) { - var db = scope.ServiceProvider.GetRequiredService(); if (db.Database.CanConnect()) { try @@ -91,6 +90,15 @@ namespace Oqtane.Infrastructure IsNewTenant = false }; + //If doing an Upgrade we may only have a connectionString. If that is the case - default databaseType to SqlServer + if (!string.IsNullOrEmpty(install.ConnectionString) && string.IsNullOrEmpty(install.DatabaseType)) + { + install.DatabaseType = "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer"; + install.DatabasePackage = "Oqtane.Database.SqlServer"; + InstallDatabase(install); + UpdateDatabaseType(install.DatabaseType); + } + var installation = IsInstalled(); if (!installation.Success) { @@ -183,29 +191,45 @@ namespace Oqtane.Infrastructure try { - //Rename bak extension - var packageFolderName = "Packages"; - var webRootPath = _environment.WebRootPath; - var packagesFolder = new DirectoryInfo(Path.Combine(webRootPath, packageFolderName)); + var databaseType = install.DatabaseType; - // iterate through Nuget packages in source folder - foreach (var package in packagesFolder.GetFiles("*.nupkg.bak")) + //Get database Type + var type = Type.GetType(databaseType); + + //Deploy the database components (if necessary) + if (type == null) { - if (package.Name.StartsWith(install.DatabasePackage)) + //Rename bak extension + var packageFolderName = "Packages"; + var webRootPath = _environment.WebRootPath; + var packagesFolder = new DirectoryInfo(Path.Combine(webRootPath, packageFolderName)); + + // iterate through Nuget packages in source folder + foreach (var package in packagesFolder.GetFiles("*.nupkg.bak")) { - //rename file - var packageName = Path.Combine(package.DirectoryName, package.Name); - packageName = packageName.Substring(0, packageName.IndexOf(".bak")); - package.MoveTo(packageName, true); + if (package.Name.StartsWith(install.DatabasePackage)) + { + //rename file + var packageName = Path.Combine(package.DirectoryName, package.Name); + packageName = packageName.Substring(0, packageName.IndexOf(".bak")); + package.MoveTo(packageName, true); + } } - } - //Call InstallationManager to install Database Package - using (var scope = _serviceScopeFactory.CreateScope()) - { - var installationManager = scope.ServiceProvider.GetRequiredService(); - installationManager.InstallPackages(); - result.Success = true; + //Call InstallationManager to install Database Package + using (var scope = _serviceScopeFactory.CreateScope()) + { + var installationManager = scope.ServiceProvider.GetRequiredService(); + installationManager.InstallPackages(); + + var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); + var assembliesFolder = new DirectoryInfo(assemblyPath); + var assemblyFile = new FileInfo($"{assembliesFolder}/{install.DatabasePackage}.dll"); + + AssemblyLoadContext.Default.LoadOqtaneAssembly(assemblyFile); + + result.Success = true; + } } } catch (Exception ex) @@ -224,24 +248,13 @@ namespace Oqtane.Infrastructure { try { + InstallDatabase(install); + var databaseType = install.DatabaseType; //Get database Type var type = Type.GetType(databaseType); - //Deploy the database components (if necessary) - if (type == null) - { - InstallDatabase(install); - - var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); - var assembliesFolder = new DirectoryInfo(assemblyPath); - var assemblyFile = new FileInfo($"{assembliesFolder}/{install.DatabasePackage}.dll"); - - AssemblyLoadContext.Default.LoadOqtaneAssembly(assemblyFile); - type = Type.GetType(databaseType); - } - //Create database object from Type var database = Activator.CreateInstance(type) as IDatabase; @@ -288,7 +301,7 @@ namespace Oqtane.Infrastructure using (var masterDbContext = new MasterDBContext(new DbContextOptions(), null, _config)) { - if (installation.Success && (install.DatabaseType == "SqlServer" || install.DatabaseType == "LocalDB")) + if (installation.Success && (install.DatabaseType == "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer")) { UpgradeSqlServer(sql, install.ConnectionString, install.DatabaseType, true); } @@ -397,7 +410,7 @@ namespace Oqtane.Infrastructure { using (var tenantDbContext = new TenantDBContext(tenantManager, null)) { - if (install.DatabaseType == "SqlServer" || install.DatabaseType == "LocalDB") + if (install.DatabaseType == "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer") { UpgradeSqlServer(sql, tenant.DBConnectionString, tenant.DBType, false); } diff --git a/Oqtane.Server/Migrations/01000000_InitializeTenant.cs b/Oqtane.Server/Migrations/01000000_InitializeTenant.cs index 426e53f5..03fe36a1 100644 --- a/Oqtane.Server/Migrations/01000000_InitializeTenant.cs +++ b/Oqtane.Server/Migrations/01000000_InitializeTenant.cs @@ -24,7 +24,7 @@ namespace Oqtane.Migrations siteEntityBuilder.Create(); //Add Column to Site table (for Sql Server only) we will drop it later for Sql Server only - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { siteEntityBuilder.AddStringColumn("DefaultLayoutType", 200, true); } @@ -35,7 +35,7 @@ namespace Oqtane.Migrations pageEntityBuilder.AddIndex("IX_Page", new [] {"SiteId", "Path", "UserId"}, true); //Add Columns to Page table (for Sql Server only) we will drop them later for Sql Server only - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { pageEntityBuilder.AddBooleanColumn("EditMode"); pageEntityBuilder.AddStringColumn("LayoutType", 200, true); diff --git a/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs b/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs index 17045d8d..5c6ad70d 100644 --- a/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs +++ b/Oqtane.Server/Migrations/01000201_DropColumnFromPage.cs @@ -19,7 +19,7 @@ namespace Oqtane.Migrations protected override void Up(MigrationBuilder migrationBuilder) { //Drop Column from Page table - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropColumn("EditMode"); diff --git a/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs b/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs index b9c6e11b..98a303c6 100644 --- a/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs +++ b/Oqtane.Server/Migrations/02000001_AddColumnToProfileAndUpdatePage.cs @@ -26,7 +26,7 @@ namespace Oqtane.Migrations profileEntityBuilder.UpdateColumn("Options", "''"); //Alter Column in Page table for Sql Server - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropIndex("IX_Page"); @@ -42,7 +42,7 @@ namespace Oqtane.Migrations profileEntityBuilder.DropColumn("Options"); //Alter Column in Page table - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { var pageEntityBuilder = new PageEntityBuilder(migrationBuilder, ActiveDatabase); pageEntityBuilder.DropIndex("IX_Page"); diff --git a/Oqtane.Server/Migrations/02000202_UpdateDefaultContainerTypeInSitePage.cs b/Oqtane.Server/Migrations/02000202_UpdateDefaultContainerTypeInSitePage.cs index 96c645b6..66365954 100644 --- a/Oqtane.Server/Migrations/02000202_UpdateDefaultContainerTypeInSitePage.cs +++ b/Oqtane.Server/Migrations/02000202_UpdateDefaultContainerTypeInSitePage.cs @@ -18,7 +18,7 @@ namespace Oqtane.Migrations protected override void Up(MigrationBuilder migrationBuilder) { - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { //Update DefaultContainerType In Site var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase); diff --git a/Oqtane.Server/Migrations/02000203_DropDefaultLayoutInSite.cs b/Oqtane.Server/Migrations/02000203_DropDefaultLayoutInSite.cs index c97f93ac..27424547 100644 --- a/Oqtane.Server/Migrations/02000203_DropDefaultLayoutInSite.cs +++ b/Oqtane.Server/Migrations/02000203_DropDefaultLayoutInSite.cs @@ -18,7 +18,7 @@ namespace Oqtane.Migrations protected override void Up(MigrationBuilder migrationBuilder) { - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { //Alter Column in Setting table for Sql Server var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); diff --git a/Oqtane.Server/Migrations/02010000_AddAppVersionsTableInTenant.cs b/Oqtane.Server/Migrations/02010000_AddAppVersionsTableInTenant.cs index cdea050b..7b5f8148 100644 --- a/Oqtane.Server/Migrations/02010000_AddAppVersionsTableInTenant.cs +++ b/Oqtane.Server/Migrations/02010000_AddAppVersionsTableInTenant.cs @@ -24,7 +24,7 @@ namespace Oqtane.Migrations appVersionsEntityBuilder.Create(); //Finish SqlServer Migration from DbUp - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { //Version 1.0.0 InsertVersion(migrationBuilder, "01.00.00", "Oqtane.Scripts.Master.00.09.00.00.sql"); diff --git a/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs b/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs index 044e6bf3..32d84b49 100644 --- a/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs +++ b/Oqtane.Server/Migrations/02010001_AddDatabaseTypeColumnToTenant.cs @@ -23,9 +23,9 @@ namespace Oqtane.Migrations tenantEntityBuilder.AddStringColumn("DBType", 200, true); //Update new column if SqlServer (Other Databases will not have any records yet) - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { - tenantEntityBuilder.UpdateColumn("DBType", "'SqlServer'"); + tenantEntityBuilder.UpdateColumn("DBType", $"'{ActiveDatabase.TypeName}'"); } } } diff --git a/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs index a40ff01b..5fa496dd 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/PageEntityBuilder.cs @@ -26,7 +26,7 @@ namespace Oqtane.Migrations.EntityBuilders { PageId = AddAutoIncrementColumn(table,"PageId"); SiteId = AddIntegerColumn(table,"SiteId"); - if (ActiveDatabase.Name == "SqlServer" || ActiveDatabase.Name == "LocalDB") + if (ActiveDatabase.Name == "SqlServer") { Path = AddStringColumn(table,"Path", 50); } diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Blogs.log b/Oqtane.Server/wwwroot/Packages/Oqtane.Blogs.log deleted file mode 100644 index cbd320d1..00000000 --- a/Oqtane.Server/wwwroot/Packages/Oqtane.Blogs.log +++ /dev/null @@ -1 +0,0 @@ -["C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.dll","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.pdb","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.dll","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.pdb","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.dll","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.pdb","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.css","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.js"] \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.log b/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.log deleted file mode 100644 index 9be42acf..00000000 --- a/Oqtane.Server/wwwroot/Packages/Oqtane.Database.SqlServer.log +++ /dev/null @@ -1 +0,0 @@ -["C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Database.SqlServer.dll","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Database.SqlServer.pdb","C:\\Users\\Shaun.Walker\\source\\repos\\sbwalker\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Microsoft.EntityFrameworkCore.SqlServer.dll"] \ No newline at end of file diff --git a/Oqtane.Test/Oqtane.Database.SqlServer/LocalDbDatabaseTests.cs b/Oqtane.Test/Oqtane.Database.SqlServer/LocalDbDatabaseTests.cs deleted file mode 100644 index 74856bd8..00000000 --- a/Oqtane.Test/Oqtane.Database.SqlServer/LocalDbDatabaseTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Xunit; - -namespace Oqtane.Database.SqlServer.Tests -{ - public class LocalDbDatabaseTests - { - [Fact()] - public void VerifyDatabaseTypeName() - { - // Arrange & Act - var database = new LocalDbDatabase(); - - // Assert - Assert.Equal("Oqtane.Database.SqlServer.LocalDbDatabase, Oqtane.Database.SqlServer", database.TypeName); - } - } -}