fix #2567 - migrate tenant connection string details from database to appsettings.json

This commit is contained in:
Shaun Walker
2023-02-23 16:29:15 -05:00
parent 71dd00da0f
commit f2df8e96db
33 changed files with 562 additions and 309 deletions

View File

@ -52,7 +52,7 @@ namespace Oqtane.Controllers
{
var installation = new Installation { Success = false, Message = "" };
if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || string.IsNullOrEmpty(_configManager.GetSetting("ConnectionStrings:" + SettingKeys.ConnectionStringKey, ""))))
if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || string.IsNullOrEmpty(_configManager.GetSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", ""))))
{
installation = _databaseManager.Install(config);

View File

@ -32,13 +32,23 @@ namespace Oqtane.Controllers
{
var results = new List<Dictionary<string, string>>();
Dictionary<string, string> row;
Tenant tenant = _tenants.GetTenant(sqlquery.TenantId);
if (string.IsNullOrEmpty(sqlquery.DBType) || string.IsNullOrEmpty(sqlquery.DBConnectionString))
{
Tenant tenant = _tenants.GetTenant(sqlquery.TenantId);
if (tenant != null)
{
sqlquery.DBType = tenant.DBType;
sqlquery.DBConnectionString = tenant.DBConnectionString;
}
}
try
{
foreach (string query in sqlquery.Query.Split("GO", StringSplitOptions.RemoveEmptyEntries))
{
IDataReader dr = _sql.ExecuteReader(tenant, query);
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId}", query, sqlquery.TenantId);
IDataReader dr = _sql.ExecuteReader(sqlquery.DBType, sqlquery.DBConnectionString, query);
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Sql Query {Query} Executed on Database {DBType} and Connection {DBConnectionString}", query, sqlquery.DBType, sqlquery.DBConnectionString);
while (dr.Read())
{
row = new Dictionary<string, string>();
@ -53,7 +63,7 @@ namespace Oqtane.Controllers
catch (Exception ex)
{
results.Add(new Dictionary<string, string>() { { "Error", ex.Message } });
_logger.Log(LogLevel.Warning, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId} Resulted In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
_logger.Log(LogLevel.Warning, this, LogFunction.Other, "Sql Query {Query} Executed on Database {DBType} and Connection {DBConnectionString} Resulted In An Error {Error}", sqlquery.Query, sqlquery.DBType, sqlquery.DBConnectionString, ex.Message);
}
sqlquery.Results = results;
return sqlquery;

View File

@ -63,6 +63,12 @@ namespace Oqtane.Controllers
}
systeminfo.Add("Log", log);
break;
case "connectionstrings":
foreach (var kvp in _configManager.GetSettings(SettingKeys.ConnectionStringsSection))
{
systeminfo.Add(kvp.Key, kvp.Value);
}
break;
}
return systeminfo;
@ -88,19 +94,11 @@ namespace Oqtane.Controllers
}
}
// PUT: api/<controller>
[HttpPut("{key}/{value}")]
[Authorize(Roles = RoleNames.Host)]
public void Put(string key, object value)
{
UpdateSetting(key, value);
}
private void UpdateSetting(string key, object value)
{
switch (key)
switch (key.ToLower())
{
case "Log":
case "clearlog":
string path = Path.Combine(_environment.ContentRootPath, "Content", "Log", "error.log");
if (System.IO.File.Exists(path))
{

View File

@ -72,6 +72,7 @@ namespace Microsoft.Extensions.DependencyInjection
internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services)
{
services.AddTransient<IDBContextDependencies, DBContextDependencies>();
services.AddTransient<ITenantManager, TenantManager>();
services.AddTransient<IAliasAccessor, AliasAccessor>();
services.AddTransient<IUserPermissions, UserPermissions>();

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Extensions.Configuration;
@ -42,6 +44,16 @@ namespace Oqtane.Infrastructure
return value;
}
public Dictionary<string, string> GetSettings(string sectionKey)
{
var settings = new Dictionary<string, string>();
foreach (var kvp in _config.GetSection(sectionKey).GetChildren().AsEnumerable())
{
settings.Add(kvp.Key, kvp.Value);
}
return settings;
}
public void AddOrUpdateSetting<T>(string key, T value, bool reload)
{
AddOrUpdateSetting("appsettings.json", key, value, reload);

View File

@ -162,6 +162,16 @@ namespace Oqtane.Infrastructure
{
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
}
// add new site
if (install.TenantName != TenantNames.Master && install.ConnectionString.Contains("="))
{
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{install.TenantName}", install.ConnectionString, false);
}
if (install.TenantName == TenantNames.Master && !install.ConnectionString.Contains("="))
{
install.ConnectionString = _config.GetConnectionString(install.ConnectionString);
}
}
else
{
@ -273,7 +283,7 @@ namespace Oqtane.Infrastructure
var database = Activator.CreateInstance(type) as IDatabase;
// create data directory if does not exist
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString();
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty);
var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options;
@ -316,10 +326,7 @@ namespace Oqtane.Infrastructure
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), null, _config))
{
if (installation.Success && (install.DatabaseType == Constants.DefaultDBType))
{
UpgradeSqlServer(sql, install.ConnectionString, install.DatabaseType, true);
}
AddEFMigrationsHistory(sql, install.ConnectionString, install.DatabaseType, "", true);
// push latest model into database
masterDbContext.Database.Migrate();
result.Success = true;
@ -354,7 +361,7 @@ namespace Oqtane.Infrastructure
tenant = new Tenant
{
Name = install.TenantName,
DBConnectionString = DenormalizeConnectionString(install.ConnectionString),
DBConnectionString = (install.TenantName == TenantNames.Master) ? SettingKeys.ConnectionStringKey : install.TenantName,
DBType = install.DatabaseType,
CreatedBy = "",
CreatedOn = DateTime.UtcNow,
@ -413,21 +420,19 @@ namespace Oqtane.Infrastructure
var upgrades = scope.ServiceProvider.GetRequiredService<IUpgradeManager>();
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
var DBContextDependencies = scope.ServiceProvider.GetRequiredService<IDBContextDependencies>();
using (var db = GetInstallationContext())
{
foreach (var tenant in db.Tenant.ToList())
{
tenantManager.SetTenant(tenant.TenantId);
tenant.DBConnectionString = MigrateConnectionString(db, tenant);
try
{
using (var tenantDbContext = new TenantDBContext(tenantManager, null))
using (var tenantDbContext = new TenantDBContext(DBContextDependencies))
{
if (install.DatabaseType == Constants.DefaultDBType)
{
UpgradeSqlServer(sql, tenant.DBConnectionString, tenant.DBType, false);
}
AddEFMigrationsHistory(sql, _configManager.GetSetting($"{SettingKeys.ConnectionStringsSection}:{tenant.DBConnectionString}", ""), tenant.DBType, tenant.Version, false);
// push latest model into database
tenantDbContext.Database.Migrate();
result.Success = true;
@ -753,8 +758,8 @@ namespace Oqtane.Infrastructure
private string DenormalizeConnectionString(string connectionString)
{
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, "|DataDirectory|");
var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString();
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, $"|{Constants.DataDirectory}|");
return connectionString;
}
@ -780,8 +785,8 @@ namespace Oqtane.Infrastructure
private string NormalizeConnectionString(string connectionString)
{
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
connectionString = connectionString.Replace("|DataDirectory|", dataDirectory);
var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString();
connectionString = connectionString.Replace($"|{Constants.DataDirectory}|", dataDirectory);
return connectionString;
}
@ -799,14 +804,39 @@ namespace Oqtane.Infrastructure
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
}
public void UpgradeSqlServer(ISqlRepository sql, string connectionString, string databaseType, bool isMaster)
public void AddEFMigrationsHistory(ISqlRepository sql, string connectionString, string databaseType, string version, bool isMaster)
{
var script = (isMaster) ? "MigrateMaster.sql" : "MigrateTenant.sql";
// in version 2.1.0 the __EFMigrationsHistory tables were introduced and must be added to existing SQL Server installations
if ((isMaster || (version != null && Version.Parse(version).CompareTo(Version.Parse("2.1.0")) < 0)) && databaseType == Constants.DefaultDBType)
{
var script = (isMaster) ? "MigrateMaster.sql" : "MigrateTenant.sql";
var query = sql.GetScriptFromAssembly(Assembly.GetExecutingAssembly(), script);
query = query.Replace("{{Version}}", Constants.Version);
var query = sql.GetScriptFromAssembly(Assembly.GetExecutingAssembly(), script);
query = query.Replace("{{Version}}", Constants.Version);
sql.ExecuteNonQuery(connectionString, databaseType, query);
sql.ExecuteNonQuery(connectionString, databaseType, query);
}
}
public string MigrateConnectionString(InstallationContext db, Tenant tenant)
{
// migrate connection strings from the Tenant table to appsettings
if (tenant.DBConnectionString.Contains("="))
{
var defaultConnection = _configManager.GetConnectionString(SettingKeys.ConnectionStringKey);
if (tenant.DBConnectionString == defaultConnection)
{
tenant.DBConnectionString = SettingKeys.ConnectionStringKey;
}
else
{
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{tenant.Name}", tenant.DBConnectionString, false);
tenant.DBConnectionString = tenant.Name;
}
db.Entry(tenant).State = EntityState.Modified;
db.SaveChanges();
}
return tenant.DBConnectionString;
}
private void ValidateConfiguration()

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
namespace Oqtane.Infrastructure
@ -7,6 +8,7 @@ namespace Oqtane.Infrastructure
public IConfigurationSection GetSection(string sectionKey);
public T GetSetting<T>(string settingKey, T defaultValue);
public T GetSetting<T>(string sectionKey, string settingKey, T defaultValue);
public Dictionary<string, string> GetSettings(string sectionKey);
void AddOrUpdateSetting<T>(string key, T value, bool reload);
void AddOrUpdateSetting<T>(string file, string key, T value, bool reload);
void RemoveSetting(string key, bool reload);

View File

@ -2,7 +2,6 @@ using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Modules.HtmlText.Repository;
using System.Net;
using Microsoft.AspNetCore.Http;
using Oqtane.Enums;
using Oqtane.Repository;
using Oqtane.Shared;
@ -17,15 +16,13 @@ namespace Oqtane.Modules.HtmlText.Manager
public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable
{
private readonly IHtmlTextRepository _htmlText;
private readonly ITenantManager _tenantManager;
private readonly IHttpContextAccessor _accessor;
private readonly IDBContextDependencies _DBContextDependencies;
private readonly ISqlRepository _sqlRepository;
public HtmlTextManager(IHtmlTextRepository htmlText, ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor, ISqlRepository sqlRepository)
public HtmlTextManager(IHtmlTextRepository htmlText, IDBContextDependencies DBContextDependencies, ISqlRepository sqlRepository)
{
_htmlText = htmlText;
_tenantManager = tenantManager;
_accessor = httpContextAccessor;
_DBContextDependencies = DBContextDependencies;
_sqlRepository = sqlRepository;
}
@ -56,12 +53,12 @@ namespace Oqtane.Modules.HtmlText.Manager
// version 1.0.0 used SQL scripts rather than migrations, so we need to seed the migration history table
_sqlRepository.ExecuteNonQuery(tenant, MigrationUtils.BuildInsertScript("HtmlText.01.00.00.00"));
}
return Migrate(new HtmlTextContext(_tenantManager, _accessor), tenant, MigrationType.Up);
return Migrate(new HtmlTextContext(_DBContextDependencies), tenant, MigrationType.Up);
}
public bool Uninstall(Tenant tenant)
{
return Migrate(new HtmlTextContext(_tenantManager, _accessor), tenant, MigrationType.Down);
return Migrate(new HtmlTextContext(_DBContextDependencies), tenant, MigrationType.Down);
}
}
}

View File

@ -13,7 +13,7 @@ namespace Oqtane.Modules.HtmlText.Repository
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
public class HtmlTextContext : DBContextBase, ITransientService, IMultiDatabase
{
public HtmlTextContext(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) : base(tenantManager, httpContextAccessor) { }
public HtmlTextContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
public virtual DbSet<Models.HtmlText> HtmlText { get; set; }
}

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
@ -6,11 +7,13 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Configuration;
using Oqtane.Databases.Interfaces;
using Oqtane.Extensions;
using Oqtane.Infrastructure;
using Oqtane.Migrations.Framework;
using Oqtane.Models;
using Oqtane.Shared;
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
@ -18,17 +21,17 @@ namespace Oqtane.Repository
{
public class DBContextBase : IdentityUserContext<IdentityUser>
{
private readonly ITenantResolver _tenantResolver;
private readonly ITenantManager _tenantManager;
private readonly IHttpContextAccessor _accessor;
private string _connectionString;
private string _databaseType;
private readonly IConfigurationRoot _config;
private string _connectionString = "";
private string _databaseType = "";
public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor)
public DBContextBase(IDBContextDependencies DBContextDependencies)
{
_connectionString = String.Empty;
_tenantManager = tenantManager;
_accessor = httpContextAccessor;
_tenantManager = DBContextDependencies.TenantManager;
_accessor = DBContextDependencies.Accessor;
_config = DBContextDependencies.Config;
}
public IDatabase ActiveDatabase { get; set; }
@ -39,21 +42,11 @@ namespace Oqtane.Repository
if (string.IsNullOrEmpty(_connectionString))
{
Tenant tenant;
if (_tenantResolver != null)
{
tenant = _tenantResolver.GetTenant();
}
else
{
tenant = _tenantManager.GetTenant();
}
Tenant tenant = _tenantManager.GetTenant();
if (tenant != null)
{
_connectionString = tenant.DBConnectionString
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
_connectionString = _config.GetConnectionString(tenant.DBConnectionString)
.Replace($"|{Constants.DataDirectory}|", AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString());
_databaseType = tenant.DBType;
}
}
@ -93,12 +86,17 @@ namespace Oqtane.Repository
return base.SaveChangesAsync(cancellationToken);
}
[Obsolete("This constructor is obsolete. Use DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) instead.", false)]
public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor)
[Obsolete("This constructor is obsolete. Use DBContextBase(IDBContextDependencies DBContextDependencies) instead.", false)]
public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor)
{
_connectionString = String.Empty;
_tenantResolver = tenantResolver;
_tenantManager = tenantManager;
_accessor = httpContextAccessor;
// anti-pattern used to reference config service in base class without causing breaking change
_config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
}
}
}

View File

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Oqtane.Infrastructure;
namespace Oqtane.Repository
{
public class DBContextDependencies : IDBContextDependencies
{
public DBContextDependencies(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor, IConfigurationRoot config)
{
TenantManager = tenantManager;
Accessor = httpContextAccessor;
Config = config;
}
public ITenantManager TenantManager { get; }
public IHttpContextAccessor Accessor { get; }
public IConfigurationRoot Config { get; }
}
}

View File

@ -1,8 +1,5 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Oqtane.Databases.Interfaces;
using Microsoft.EntityFrameworkCore;
using Oqtane.Extensions;
using Oqtane.Interfaces;
using Oqtane.Models;
using IDatabase = Oqtane.Databases.Interfaces.IDatabase;

View File

@ -41,8 +41,8 @@ namespace Oqtane.Repository
{
if (_config.IsInstalled())
{
_connectionString = _config.GetConnectionString("DefaultConnection")
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
_connectionString = _config.GetConnectionString(SettingKeys.ConnectionStringKey)
.Replace($"|{Constants.DataDirectory}|", AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString());
}
_databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];

View File

@ -1,6 +1,4 @@
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Repository.Databases.Interfaces;
@ -12,7 +10,7 @@ namespace Oqtane.Repository
{
public class TenantDBContext : DBContextBase, IMultiDatabase
{
public TenantDBContext(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) : base(tenantManager, httpContextAccessor) { }
public TenantDBContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
public virtual DbSet<Site> Site { get; set; }
public virtual DbSet<Page> Page { get; set; }

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Oqtane.Infrastructure;
namespace Oqtane.Repository
{
public interface IDBContextDependencies
{
ITenantManager TenantManager { get; }
IHttpContextAccessor Accessor { get; }
IConfigurationRoot Config { get; }
}
}

View File

@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Reflection;
using Oqtane.Models;
@ -18,6 +18,8 @@ namespace Oqtane.Repository
IDataReader ExecuteReader(Tenant tenant, string query);
IDataReader ExecuteReader(string DBType, string DBConnectionString, string query);
string GetScriptFromAssembly(Assembly assembly, string fileName);
}
}

View File

@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.Configuration;
using Oqtane.Databases.Interfaces;
using Oqtane.Interfaces;
using Oqtane.Models;
// ReSharper disable ConvertToUsingDeclaration
// ReSharper disable InvertIf
@ -15,6 +14,13 @@ namespace Oqtane.Repository
{
public class SqlRepository : ISqlRepository
{
private IConfigurationRoot _config;
public SqlRepository(IConfigurationRoot config)
{
_config = config;
}
public void ExecuteScript(Tenant tenant, string script)
{
// execute script in current tenant
@ -75,13 +81,19 @@ namespace Oqtane.Repository
public IDataReader ExecuteReader(Tenant tenant, string query)
{
var db = GetActiveDatabase(tenant.DBType);
return db.ExecuteReader(tenant.DBConnectionString, query);
return db.ExecuteReader(GetConnectionString(tenant.DBConnectionString), query);
}
public IDataReader ExecuteReader(string DBType, string DBConnectionString, string query)
{
var db = GetActiveDatabase(DBType);
return db.ExecuteReader(GetConnectionString(DBConnectionString), query);
}
public int ExecuteNonQuery(string connectionString, string databaseType, string query)
{
var db = GetActiveDatabase(databaseType);
return db.ExecuteNonQuery(connectionString, query);
return db.ExecuteNonQuery(GetConnectionString(connectionString), query);
}
public string GetScriptFromAssembly(Assembly assembly, string fileName)
@ -119,5 +131,14 @@ namespace Oqtane.Repository
return activeDatabase;
}
private string GetConnectionString(string connectionString)
{
if (!connectionString.Contains("="))
{
connectionString = _config.GetConnectionString(connectionString);
}
return connectionString;
}
}
}

View File

@ -40,7 +40,7 @@ namespace Oqtane
//add possibility to switch off swagger on production.
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data"));
AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(env.ContentRootPath, "Data"));
_env = env;
}

View File

@ -12,25 +12,23 @@ namespace [Owner].[Module].Manager
{
public class [Module]Manager : MigratableModuleBase, IInstallable, IPortable
{
private I[Module]Repository _[Module]Repository;
private readonly ITenantManager _tenantManager;
private readonly IHttpContextAccessor _accessor;
private readonly I[Module]Repository _[Module]Repository;
private readonly IDBContextDependencies _DBContextDependencies;
public [Module]Manager(I[Module]Repository [Module]Repository, ITenantManager tenantManager, IHttpContextAccessor accessor)
public [Module]Manager(I[Module]Repository [Module]Repository, IDBContextDependencies DBContextDependencies)
{
_[Module]Repository = [Module]Repository;
_tenantManager = tenantManager;
_accessor = accessor;
_DBContextDependencies = DBContextDependencies;
}
public bool Install(Tenant tenant, string version)
{
return Migrate(new [Module]Context(_tenantManager, _accessor), tenant, MigrationType.Up);
return Migrate(new [Module]Context(_DBContextDependencies), tenant, MigrationType.Up);
}
public bool Uninstall(Tenant tenant)
{
return Migrate(new [Module]Context(_tenantManager, _accessor), tenant, MigrationType.Down);
return Migrate(new [Module]Context(_DBContextDependencies), tenant, MigrationType.Down);
}
public string ExportModule(Module module)

View File

@ -11,7 +11,7 @@ namespace [Owner].[Module].Repository
{
public virtual DbSet<Models.[Module]> [Module] { get; set; }
public [Module]Context(ITenantManager tenantManager, IHttpContextAccessor accessor) : base(tenantManager, accessor)
public [Module]Context(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
{
// ContextBase handles multi-tenant database connections
}