diff --git a/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs b/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs new file mode 100644 index 00000000..e34d1563 --- /dev/null +++ b/Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore; + +namespace Oqtane.Extensions +{ + public static class DbContextOptionsBuilderExtensions + { + public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, string connectionString) + { + optionsBuilder.UseSqlServer(connectionString); + + return optionsBuilder; + } + } +} diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 35f93353..308b5cf0 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -168,9 +168,10 @@ namespace Oqtane.Infrastructure var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory); - using (var dbc = new DbContext(new DbContextOptionsBuilder().UseSqlServer(NormalizeConnectionString(install.ConnectionString)).Options)) + var connectionString = NormalizeConnectionString(install.ConnectionString); + using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(connectionString).Options)) { - // create empty database if it does not exist + // create empty database if it does not exist dbc.Database.EnsureCreated(); result.Success = true; } @@ -235,7 +236,7 @@ namespace Oqtane.Infrastructure if (!string.IsNullOrEmpty(install.TenantName) && !string.IsNullOrEmpty(install.Aliases)) { - using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))) + using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))) { Tenant tenant; if (install.IsNewTenant) @@ -274,7 +275,7 @@ namespace Oqtane.Infrastructure using (var scope = _serviceScopeFactory.CreateScope()) { var upgrades = scope.ServiceProvider.GetRequiredService(); - + using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))) { foreach (var tenant in db.Tenant.ToList()) diff --git a/Oqtane.Server/Repository/Context/DBContextBase.cs b/Oqtane.Server/Repository/Context/DBContextBase.cs index 522bf0d9..9d488f45 100644 --- a/Oqtane.Server/Repository/Context/DBContextBase.cs +++ b/Oqtane.Server/Repository/Context/DBContextBase.cs @@ -4,11 +4,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; +using Oqtane.Extensions; using Oqtane.Models; namespace Oqtane.Repository { - public class DBContextBase : IdentityUserContext + public class DBContextBase : IdentityUserContext { private ITenantResolver _tenantResolver; private IHttpContextAccessor _accessor; @@ -24,63 +25,16 @@ namespace Oqtane.Repository var tenant = _tenantResolver.GetTenant(); if (tenant != null) { - optionsBuilder.UseSqlServer(tenant.DBConnectionString - .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()) - ); + var connectionString = tenant.DBConnectionString + .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()); + optionsBuilder.UseOqtaneDatabase(connectionString); } base.OnConfiguring(optionsBuilder); } public override int SaveChanges() { - ChangeTracker.DetectChanges(); - - string username = ""; - if (_accessor.HttpContext != null && _accessor.HttpContext.User.Identity.Name != null) - { - username = _accessor.HttpContext.User.Identity.Name; - } - DateTime date = DateTime.UtcNow; - - var created = ChangeTracker.Entries() - .Where(x => x.State == EntityState.Added); - - foreach(var item in created) - { - if (item.Entity is IAuditable) - { - item.CurrentValues[nameof(IAuditable.CreatedBy)] = username; - item.CurrentValues[nameof(IAuditable.CreatedOn)] = date; - } - } - - var modified = ChangeTracker.Entries() - .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added); - - foreach (var item in modified) - { - if (item.Entity is IAuditable) - { - item.CurrentValues[nameof(IAuditable.ModifiedBy)] = username; - item.CurrentValues[nameof(IAuditable.ModifiedOn)] = date; - } - - if (item.Entity is IDeletable && item.State != EntityState.Added) - { - if ((bool)item.CurrentValues[nameof(IDeletable.IsDeleted)] - && !item.GetDatabaseValues().GetValue(nameof(IDeletable.IsDeleted))) - { - item.CurrentValues[nameof(IDeletable.DeletedBy)] = username; - item.CurrentValues[nameof(IDeletable.DeletedOn)] = date; - } - else if (!(bool)item.CurrentValues[nameof(IDeletable.IsDeleted)] - && item.GetDatabaseValues().GetValue(nameof(IDeletable.IsDeleted))) - { - item.CurrentValues[nameof(IDeletable.DeletedBy)] = null; - item.CurrentValues[nameof(IDeletable.DeletedOn)] = null; - } - } - } + DbContextUtils.SaveChanges(this, _accessor); return base.SaveChanges(); } diff --git a/Oqtane.Server/Repository/Context/DbContextUtils.cs b/Oqtane.Server/Repository/Context/DbContextUtils.cs new file mode 100644 index 00000000..1b4014cb --- /dev/null +++ b/Oqtane.Server/Repository/Context/DbContextUtils.cs @@ -0,0 +1,65 @@ +using System; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Oqtane.Models; + +namespace Oqtane.Repository +{ + public class DbContextUtils + { + public static void SaveChanges(DbContext context, IHttpContextAccessor accessor) + { + var changeTracker = context.ChangeTracker; + + changeTracker.DetectChanges(); + + string username = ""; + if (accessor.HttpContext != null && accessor.HttpContext.User.Identity.Name != null) + { + username = accessor.HttpContext.User.Identity.Name; + } + DateTime date = DateTime.UtcNow; + + var created = changeTracker.Entries() + .Where(x => x.State == EntityState.Added); + + foreach(var item in created) + { + if (item.Entity is IAuditable) + { + item.CurrentValues[nameof(IAuditable.CreatedBy)] = username; + item.CurrentValues[nameof(IAuditable.CreatedOn)] = date; + } + } + + var modified = changeTracker.Entries() + .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added); + + foreach (var item in modified) + { + if (item.Entity is IAuditable) + { + item.CurrentValues[nameof(IAuditable.ModifiedBy)] = username; + item.CurrentValues[nameof(IAuditable.ModifiedOn)] = date; + } + + if (item.Entity is IDeletable && item.State != EntityState.Added) + { + if ((bool)item.CurrentValues[nameof(IDeletable.IsDeleted)] + && !item.GetDatabaseValues().GetValue(nameof(IDeletable.IsDeleted))) + { + item.CurrentValues[nameof(IDeletable.DeletedBy)] = username; + item.CurrentValues[nameof(IDeletable.DeletedOn)] = date; + } + else if (!(bool)item.CurrentValues[nameof(IDeletable.IsDeleted)] + && item.GetDatabaseValues().GetValue(nameof(IDeletable.IsDeleted))) + { + item.CurrentValues[nameof(IDeletable.DeletedBy)] = null; + item.CurrentValues[nameof(IDeletable.DeletedOn)] = null; + } + } + } + } + } +} diff --git a/Oqtane.Server/Repository/Context/InstallationContext.cs b/Oqtane.Server/Repository/Context/InstallationContext.cs index 29bfc281..6eaf5a65 100644 --- a/Oqtane.Server/Repository/Context/InstallationContext.cs +++ b/Oqtane.Server/Repository/Context/InstallationContext.cs @@ -1,10 +1,11 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.EntityFrameworkCore; +using Oqtane.Extensions; using Oqtane.Models; namespace Oqtane.Repository { - + public class InstallationContext : DbContext { private readonly string _connectionString; @@ -15,7 +16,7 @@ namespace Oqtane.Repository } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseSqlServer(_connectionString); + => optionsBuilder.UseOqtaneDatabase(_connectionString); public virtual DbSet Alias { get; set; } public virtual DbSet Tenant { get; set; } diff --git a/Oqtane.Server/Repository/Context/MasterDBContext.cs b/Oqtane.Server/Repository/Context/MasterDBContext.cs index 976874cf..dd94dedd 100644 --- a/Oqtane.Server/Repository/Context/MasterDBContext.cs +++ b/Oqtane.Server/Repository/Context/MasterDBContext.cs @@ -4,13 +4,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Oqtane.Models; using Microsoft.Extensions.Configuration; +using Oqtane.Extensions; namespace Oqtane.Repository { public class MasterDBContext : DbContext { - private IHttpContextAccessor _accessor; - private IConfiguration _configuration; + private readonly IHttpContextAccessor _accessor; + private readonly IConfiguration _configuration; public MasterDBContext(DbContextOptions options, IHttpContextAccessor accessor, IConfiguration configuration) : base(options) { @@ -20,11 +21,12 @@ namespace Oqtane.Repository protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - if (!string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) + if (!String.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection"))) { - optionsBuilder.UseSqlServer(_configuration.GetConnectionString("DefaultConnection") - .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()) - ); + var connectionString = _configuration.GetConnectionString("DefaultConnection") + .Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString()); + + optionsBuilder.UseOqtaneDatabase(connectionString); } base.OnConfiguring(optionsBuilder); } @@ -37,38 +39,7 @@ namespace Oqtane.Repository public override int SaveChanges() { - ChangeTracker.DetectChanges(); - - string username = ""; - if (_accessor.HttpContext != null && _accessor.HttpContext.User.Identity.Name != null) - { - username = _accessor.HttpContext.User.Identity.Name; - } - DateTime date = DateTime.UtcNow; - - var created = ChangeTracker.Entries() - .Where(x => x.State == EntityState.Added); - - foreach (var item in created) - { - if (item.Entity is IAuditable) - { - item.CurrentValues[nameof(IAuditable.CreatedBy)] = username; - item.CurrentValues[nameof(IAuditable.CreatedOn)] = date; - } - } - - var modified = ChangeTracker.Entries() - .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added); - - foreach (var item in modified) - { - if (item.Entity is IAuditable) - { - item.CurrentValues[nameof(IAuditable.ModifiedBy)] = username; - item.CurrentValues[nameof(IAuditable.ModifiedOn)] = date; - } - } + DbContextUtils.SaveChanges(this, _accessor); return base.SaveChanges(); }