diff --git a/Yi.Abp.Net8/Yi.Abp.sln b/Yi.Abp.Net8/Yi.Abp.sln index 9dcccd99..3791f61e 100644 --- a/Yi.Abp.Net8/Yi.Abp.sln +++ b/Yi.Abp.Net8/Yi.Abp.sln @@ -94,7 +94,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tenant-management", "tenant EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.SqlSugarCore", "module\tenant-management\Yi.Framework.TenantManagement.SqlSugarCore\Yi.Framework.TenantManagement.SqlSugarCore.csproj", "{FA5BBAA1-08DC-472F-BB2C-5314E59D1556}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.TenantManagement.Domain", "module\tenant-management\Yi.Framework.TenantManagement.Domain\Yi.Framework.TenantManagement.Domain.csproj", "{54D8E2BC-591C-4344-A58E-874D49C00B41}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManagement.Domain", "module\tenant-management\Yi.Framework.TenantManagement.Domain\Yi.Framework.TenantManagement.Domain.csproj", "{54D8E2BC-591C-4344-A58E-874D49C00B41}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs new file mode 100644 index 00000000..4aeb7766 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs @@ -0,0 +1,107 @@ +using SqlSugar; + +namespace Yi.Framework.SqlSugarCore.Abstractions +{ + public class DbConnOptions + { + /// + /// 连接字符串(如果开启多租户,也就是默认库了),必填 + /// + public string? Url { get; set; } + + /// + /// 数据库类型 + /// + public DbType? DbType { get; set; } + + /// + /// 开启种子数据 + /// + public bool EnabledDbSeed { get; set; } = false; + + + + /// + /// 开启codefirst + /// + public bool EnabledCodeFirst { get; set; } = false; + + /// + /// 开启sql日志 + /// + public bool EnabledSqlLog { get; set; } = true; + + /// + /// 实体程序集 + /// + public List? EntityAssembly { get; set; } + + /// + /// 开启读写分离 + /// + public bool EnabledReadWrite { get; set; } = false; + + /// + /// 读写分离 + /// + public List? ReadUrl { get; set; } + + /// + /// 开启Saas多租户 + /// + public bool EnabledSaasMultiTenancy { get; set; } = false; + + + /// + /// 默认租户库连接,如果不填,那就是默认库的地址 + /// + public string? MasterSaasMultiTenancyUrl { get; set; } + + + /// + /// Saas租户连接 + /// + public List? SaasMultiTenancy { get; set; } + + public static string MasterTenantDbDefaultName = "Master"; + public static string TenantDbDefaultName = "Default"; + + public SaasMultiTenancyOptions GetDefaultSaasMultiTenancy() + { + return new SaasMultiTenancyOptions { Name = TenantDbDefaultName, Url = Url }; + } + public SaasMultiTenancyOptions? GetDefaultMasterSaasMultiTenancy() + { + if (EnabledSaasMultiTenancy == false) + { + return null; + } + if (string.IsNullOrEmpty(MasterSaasMultiTenancyUrl)) + { + + return new SaasMultiTenancyOptions { Name = MasterTenantDbDefaultName, Url = Url }; + } + else + { + return new SaasMultiTenancyOptions() + { + Name = MasterTenantDbDefaultName, + Url = MasterSaasMultiTenancyUrl + }; + } + } + } + + public class SaasMultiTenancyOptions + { + /// + /// 租户名称标识 + /// + public string Name { get; set; } + + /// + /// 连接Url + /// + public string Url { get; set; } + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs index eed39e76..8fc6afa5 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContext.cs @@ -12,10 +12,12 @@ namespace Yi.Framework.SqlSugarCore.Abstractions { // IAbpLazyServiceProvider LazyServiceProvider { get; set; } ISqlSugarClient SqlSugarClient { get; } + DbConnOptions Options { get; } /// /// 数据库备份 /// void BackupDataBase(); + void SetSqlSugarClient(ISqlSugarClient sqlSugarClient); } } diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/IgnoreCodeFirstAttribute.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/IgnoreCodeFirstAttribute.cs new file mode 100644 index 00000000..c7e11169 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/IgnoreCodeFirstAttribute.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.SqlSugarCore.Abstractions +{ + [AttributeUsage(AttributeTargets.Class)] + public class IgnoreCodeFirstAttribute : Attribute + { + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/MasterTenantAttribute.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/MasterTenantAttribute.cs new file mode 100644 index 00000000..fee1dee7 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/MasterTenantAttribute.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.SqlSugarCore.Abstractions +{ + [AttributeUsage(AttributeTargets.Class)] + public class MasterTenantAttribute : Attribute + { + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/DbConnOptions.cs deleted file mode 100644 index 4beaa57b..00000000 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/DbConnOptions.cs +++ /dev/null @@ -1,49 +0,0 @@ -using SqlSugar; - -namespace Yi.Framework.SqlSugarCore -{ - public class DbConnOptions - { - /// - /// 连接字符串,必填 - /// - public string? Url { get; set; } - - /// - /// 数据库类型 - /// - public DbType? DbType { get; set; } - - /// - /// 开启种子数据 - /// - public bool EnabledDbSeed { get; set; } = false; - - /// - /// 开启读写分离 - /// - public bool EnabledReadWrite { get; set; } = false; - - /// - /// 开启codefirst - /// - public bool EnabledCodeFirst { get; set; } = false; - - /// - /// 开启sql日志 - /// - public bool EnabledSqlLog { get; set; } = true; - - /// - /// 实体程序集 - /// - public List? EntityAssembly { get; set; } - - /// - /// 读写分离 - /// - public List? ReadUrl { get; set; } - - - } -} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs index 6418bd14..292c8662 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs @@ -22,7 +22,7 @@ namespace Yi.Framework.SqlSugarCore /// /// SqlSugar 客户端 /// - public ISqlSugarClient SqlSugarClient { get; } + public ISqlSugarClient SqlSugarClient { get; private set; } public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService(); private IAbpLazyServiceProvider LazyServiceProvider { get; } @@ -36,8 +36,13 @@ namespace Yi.Framework.SqlSugarCore protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled() ?? false; public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService(NullEntityChangeEventHelper.Instance); - protected DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService>().Value; + public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService>().Value; + + public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient) + { + SqlSugarClient=sqlSugarClient; + } public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) { LazyServiceProvider = lazyServiceProvider; diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Uow/UnitOfWorkSqlsugarDbContextProvider.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Uow/UnitOfWorkSqlsugarDbContextProvider.cs index 6d83cd70..af319ea8 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Uow/UnitOfWorkSqlsugarDbContextProvider.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Uow/UnitOfWorkSqlsugarDbContextProvider.cs @@ -18,7 +18,7 @@ namespace Yi.Framework.SqlSugarCore.Uow { public class UnitOfWorkSqlsugarDbContextProvider : ISugarDbContextProvider where TDbContext : ISqlSugarDbContext { - + private readonly string MasterTenantDbDefaultName = DbConnOptions.MasterTenantDbDefaultName; public ILogger> Logger { get; set; } protected readonly IUnitOfWorkManager UnitOfWorkManager; @@ -47,17 +47,12 @@ namespace Yi.Framework.SqlSugarCore.Uow if (unitOfWork == null) { UnitOfWorkManager.Begin(true); - unitOfWork=UnitOfWorkManager.Current; + unitOfWork = UnitOfWorkManager.Current; //取消工作单元强制性 //throw new AbpException("A DbContext can only be created inside a unit of work!"); } - //var sss= unitOfWork.ServiceProvider.GetRequiredService(); - //Console.WriteLine("反户的:"+sss.SqlSugarClient.ContextID); - //return sss; - ] - - var connectionStringName = "Default"; - var connectionString = await ResolveConnectionStringAsync(null); + var connectionStringName = ConnectionStrings.DefaultConnectionStringName; + var connectionString = await ResolveConnectionStringAsync(connectionStringName); // var dbContextKey = $"{this.GetType().FullName}_{connectionString}"; var dbContextKey = "Default"; var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); @@ -77,12 +72,56 @@ namespace Yi.Framework.SqlSugarCore.Uow protected virtual async Task CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString) { - + var dbContext = await CreateDbContextAsync(unitOfWork); - // Console.WriteLine("111111:" + dbContext.SqlSugarClient.ContextID); + + //没有检测到使用多租户功能,默认使用默认库即可 + if (string.IsNullOrWhiteSpace(connectionString)) + { + connectionString = dbContext.Options.Url; + connectionStringName = DbConnOptions.TenantDbDefaultName; + } + + //获取到DB之后,对多租户多库进行处理 + var changedDbContext = DatabaseChange(dbContext, connectionStringName, connectionString); + + + return changedDbContext; + } + + protected virtual TDbContext DatabaseChange(TDbContext dbContext, string configId, string connectionString) + { + var dbOption = dbContext.Options; + var db = dbContext.SqlSugarClient.AsTenant(); + //主库的Db切换,当操作的是租户表的时候 + if (CurrentTenant.Name == MasterTenantDbDefaultName) + { + //直接切换 + configId = MasterTenantDbDefaultName; + var conStrOrNull= dbOption.GetDefaultMasterSaasMultiTenancy(); + Volo.Abp.Check.NotNull(conStrOrNull,"租户主库未找到"); + connectionString = conStrOrNull.Url; + } + + //租户Db的动态切换 + //二级缓存 + if (!db.IsAnyConnection(configId)) + { + //添加一个db到当前上下文 (Add部分不线上下文不会共享) + db.AddConnection(new ConnectionConfig() + { + DbType = dbOption.DbType!.Value, + ConfigId = configId,//设置库的唯一标识 + IsAutoCloseConnection = true, + ConnectionString = connectionString + }); + } + var currentDb = db.GetConnection(configId) as ISqlSugarClient; + dbContext.SetSqlSugarClient(currentDb); return dbContext; } + protected virtual async Task CreateDbContextAsync(IUnitOfWork unitOfWork) { return unitOfWork.ServiceProvider.GetRequiredService(); @@ -92,22 +131,22 @@ namespace Yi.Framework.SqlSugarCore.Uow } protected virtual async Task CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork) { - var transactionApiKey = $"Sqlsugar_Default"+Guid.NewGuid().ToString(); + var transactionApiKey = $"Sqlsugar_Default" + Guid.NewGuid().ToString(); var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi; //if (activeTransaction==null|| activeTransaction.Equals(default(SqlSugarTransactionApi))) //{ - var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); - var transaction = new SqlSugarTransactionApi( - dbContext - ); - unitOfWork.AddTransactionApi(transactionApiKey, transaction); + var dbContext = unitOfWork.ServiceProvider.GetRequiredService(); + var transaction = new SqlSugarTransactionApi( + dbContext + ); + unitOfWork.AddTransactionApi(transactionApiKey, transaction); - //await Console.Out.WriteLineAsync("开始新的事务"); - // Console.WriteLine(dbContext.SqlSugarClient.ContextID); - await dbContext.SqlSugarClient.Ado.BeginTranAsync(); - return dbContext; + //await Console.Out.WriteLineAsync("开始新的事务"); + // Console.WriteLine(dbContext.SqlSugarClient.ContextID); + await dbContext.SqlSugarClient.Ado.BeginTranAsync(); + return dbContext; //} //else //{ @@ -134,5 +173,6 @@ namespace Yi.Framework.SqlSugarCore.Uow return await ConnectionStringResolver.ResolveAsync(connectionStringName); } + } } diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs index f7f1a81f..d4b1e02b 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs @@ -51,6 +51,9 @@ namespace Yi.Framework.SqlSugarCore var service = context.ServiceProvider; var options = service.GetRequiredService>().Value; + + //Todo:准备支持多租户种子数据及CodeFirst + if (options.EnabledCodeFirst) { CodeFirst(service); @@ -73,7 +76,10 @@ namespace Yi.Framework.SqlSugarCore List types = new List(); foreach (var module in moduleContainer.Modules) { - types.AddRange(module.Assembly.GetTypes().Where(x => x.GetCustomAttribute() != null).Where(x => x.GetCustomAttribute() is null)); + types.AddRange(module.Assembly.GetTypes() + .Where(x => x.GetCustomAttribute() == null) + .Where(x => x.GetCustomAttribute() != null) + .Where(x => x.GetCustomAttribute() is null)); } if (types.Count > 0) { diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/SqlSugarTenantStore.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/SqlSugarTenantStore.cs index c02bcd44..684be613 100644 --- a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/SqlSugarTenantStore.cs +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/SqlSugarTenantStore.cs @@ -2,9 +2,7 @@ using Volo.Abp; using Volo.Abp.Caching; using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; -using Volo.Abp.ObjectMapping; namespace Yi.Framework.TenantManagement.Domain { @@ -96,21 +94,23 @@ namespace Yi.Framework.TenantManagement.Domain private ConnectionStrings? MaptoString(string tenantConnectionString) { - tenantConnectionString = tenantConnectionString.TrimEnd(';'); - var strSpiteds = tenantConnectionString.Split(";"); - if (strSpiteds.Count() == 0) - { - return null; + //tenantConnectionString = tenantConnectionString.TrimEnd(';'); + //var strSpiteds = tenantConnectionString.Split(";"); + //if (strSpiteds.Count() == 0) + //{ + // return null; - } + //} var connectionStrings = new ConnectionStrings(); - foreach (string strSpited in strSpiteds) - { - var key = strSpited.Split('=')[0]; - var value = strSpited.Split('=')[1]; - connectionStrings[key] = value; - } + //foreach (string strSpited in strSpiteds) + //{ + // var key = strSpited.Split('=')[0]; + // var value = strSpited.Split('=')[1]; + // connectionStrings[key] = value; + //} + connectionStrings["test"] = tenantConnectionString; + return connectionStrings; } diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantAggregateRoot.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantAggregateRoot.cs index e261b155..7dbf4739 100644 --- a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantAggregateRoot.cs +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantAggregateRoot.cs @@ -5,10 +5,12 @@ using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.TenantManagement; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.TenantManagement.Domain { [SugarTable("Tenant")] + [MasterTenant] public class TenantAggregateRoot : FullAuditedAggregateRoot, IHasEntityVersion { public TenantAggregateRoot() @@ -21,8 +23,8 @@ namespace Yi.Framework.TenantManagement.Domain SetName(name); } - [SugarColumn(IsPrimaryKey =true)] - public override Guid Id { get ; protected set; } + [SugarColumn(IsPrimaryKey = true)] + public override Guid Id { get; protected set; } public virtual string Name { get; protected set; } public int EntityVersion { get; protected set; } @@ -30,9 +32,9 @@ namespace Yi.Framework.TenantManagement.Domain public DbType DbType { get; protected set; } - [SugarColumn(IsIgnore=true)] + [SugarColumn(IsIgnore = true)] public override ExtraPropertyDictionary ExtraProperties { get => base.ExtraProperties; protected set => base.ExtraProperties = value; } - public virtual void SetConnectionString(DbType dbType,string connectionString) + public virtual void SetConnectionString(DbType dbType, string connectionString) { DbType = dbType; TenantConnectionString = connectionString; diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantManagementExtensions.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantManagementExtensions.cs new file mode 100644 index 00000000..ec37f404 --- /dev/null +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/TenantManagementExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.TenantManagement.Domain +{ + public static class TenantManagementExtensions + { + public static IDisposable ChangeMaster(this ICurrentTenant currentTenant) + { + return currentTenant.Change(null, DbConnOptions.MasterTenantDbDefaultName); + } + } +} diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/Yi.Framework.TenantManagement.Domain.csproj b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/Yi.Framework.TenantManagement.Domain.csproj index 934dbab0..4b246a2c 100644 --- a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/Yi.Framework.TenantManagement.Domain.csproj +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/Yi.Framework.TenantManagement.Domain.csproj @@ -8,7 +8,8 @@ - + + diff --git a/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/TenantConst.cs b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/TenantConst.cs new file mode 100644 index 00000000..dfd192b7 --- /dev/null +++ b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/TenantConst.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.TenantManagement.Domain.Shared +{ + public class TenantConst + { + public static string TenantDbDefaultName = "Master"; + } +} diff --git a/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/Yi.Framework.TenantManagement.Domain.Shared.csproj b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/Yi.Framework.TenantManagement.Domain.Shared.csproj new file mode 100644 index 00000000..5ce88f6d --- /dev/null +++ b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/Yi.Framework.TenantManagement.Domain.Shared.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/YiFrameworkTenantManagementDomainSharedModule.cs b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/YiFrameworkTenantManagementDomainSharedModule.cs new file mode 100644 index 00000000..d0784856 --- /dev/null +++ b/Yi.Abp.Net8/module/tenant-management/YiFrameworkTenantManagementDomain.Shared/YiFrameworkTenantManagementDomainSharedModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Modularity; +using Volo.Abp.TenantManagement; + +namespace YiFrameworkTenantManagementDomain.Shared +{ + [DependsOn(typeof(AbpTenantManagementDomainSharedModule))] + public class YiFrameworkTenantManagementDomainSharedModule : AbpModule + { + + } +} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/MultiTenantConnectionStringResolver2.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/MultiTenantConnectionStringResolver2.cs deleted file mode 100644 index 263aa0de..00000000 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/MultiTenantConnectionStringResolver2.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.MultiTenancy; - -[Dependency(ReplaceServices = true)] -public class MultiTenantConnectionStringResolver2 : DefaultConnectionStringResolver -{ - private readonly ICurrentTenant _currentTenant; - private readonly IServiceProvider _serviceProvider; - - public MultiTenantConnectionStringResolver2( - IOptionsMonitor options, - ICurrentTenant currentTenant, - IServiceProvider serviceProvider) - : base(options) - { - _currentTenant = currentTenant; - _serviceProvider = serviceProvider; - } - - public override async Task ResolveAsync(string? connectionStringName = null) - { - if (_currentTenant.Id == null) - { - //No current tenant, fallback to default logic - return await base.ResolveAsync(connectionStringName); - } - - var tenant = await FindTenantConfigurationAsync(_currentTenant.Id.Value); - - if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty()) - { - //Tenant has not defined any connection string, fallback to default logic - return await base.ResolveAsync(connectionStringName); - } - - var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default; - - //Requesting default connection string... - if (connectionStringName == null || - connectionStringName == ConnectionStrings.DefaultConnectionStringName) - { - //Return tenant's default or global default - return !tenantDefaultConnectionString.IsNullOrWhiteSpace() - ? tenantDefaultConnectionString! - : Options.ConnectionStrings.Default!; - } - - //Requesting specific connection string... - var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName); - if (!connString.IsNullOrWhiteSpace()) - { - //Found for the tenant - return connString!; - } - - //Fallback to the mapped database for the specific connection string - var database = Options.Databases.GetMappedDatabaseOrNull(connectionStringName); - if (database != null && database.IsUsedByTenants) - { - connString = tenant.ConnectionStrings?.GetOrDefault(database.DatabaseName); - if (!connString.IsNullOrWhiteSpace()) - { - //Found for the tenant - return connString!; - } - } - - //Fallback to tenant's default connection string if available - if (!tenantDefaultConnectionString.IsNullOrWhiteSpace()) - { - return tenantDefaultConnectionString!; - } - - return await base.ResolveAsync(connectionStringName); - } - - [Obsolete("Use ResolveAsync method.")] - public override string Resolve(string? connectionStringName = null) - { - if (_currentTenant.Id == null) - { - //No current tenant, fallback to default logic - return base.Resolve(connectionStringName); - } - - var tenant = FindTenantConfiguration(_currentTenant.Id.Value); - - if (tenant == null || tenant.ConnectionStrings.IsNullOrEmpty()) - { - //Tenant has not defined any connection string, fallback to default logic - return base.Resolve(connectionStringName); - } - - var tenantDefaultConnectionString = tenant.ConnectionStrings?.Default; - - //Requesting default connection string... - if (connectionStringName == null || - connectionStringName == ConnectionStrings.DefaultConnectionStringName) - { - //Return tenant's default or global default - return !tenantDefaultConnectionString.IsNullOrWhiteSpace() - ? tenantDefaultConnectionString! - : Options.ConnectionStrings.Default!; - } - - //Requesting specific connection string... - var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName); - if (!connString.IsNullOrWhiteSpace()) - { - //Found for the tenant - return connString!; - } - - //Fallback to tenant's default connection string if available - if (!tenantDefaultConnectionString.IsNullOrWhiteSpace()) - { - return tenantDefaultConnectionString!; - } - - //Try to find the specific connection string for given name - var connStringInOptions = Options.ConnectionStrings.GetOrDefault(connectionStringName); - if (!connStringInOptions.IsNullOrWhiteSpace()) - { - return connStringInOptions!; - } - - //Fallback to the global default connection string - var defaultConnectionString = Options.ConnectionStrings.Default; - if (!defaultConnectionString.IsNullOrWhiteSpace()) - { - return defaultConnectionString!; - } - - throw new AbpException("No connection string defined!"); - } - - protected virtual async Task FindTenantConfigurationAsync(Guid tenantId) - { - using (var serviceScope = _serviceProvider.CreateScope()) - { - var tenantStore = serviceScope - .ServiceProvider - .GetRequiredService(); - - return await tenantStore.FindAsync(tenantId); - } - } - - [Obsolete("Use FindTenantConfigurationAsync method.")] - protected virtual TenantConfiguration? FindTenantConfiguration(Guid tenantId) - { - using (var serviceScope = _serviceProvider.CreateScope()) - { - var tenantStore = serviceScope - .ServiceProvider - .GetRequiredService(); - - return tenantStore.Find(tenantId); - } - } -} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs index 14da5fa8..48832fce 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs @@ -1,8 +1,5 @@ -using Microsoft.Extensions.DependencyInjection.Extensions; using Serilog; using Serilog.Events; -using Volo.Abp.Data; -using Volo.Abp.MultiTenancy; using Yi.Abp.Web; //创建日志,可使用{SourceContext}记录 @@ -26,7 +23,6 @@ try builder.Host.UseAutofac(); builder.Host.UseSerilog(); await builder.Services.AddApplicationAsync(); - builder.Services.Replace(new ServiceDescriptor(typeof(IConnectionStringResolver), typeof(MultiTenantConnectionStringResolver2), ServiceLifetime.Transient)); var app = builder.Build(); await app.InitializeApplicationAsync(); await app.RunAsync(); diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index f4427b69..d42c1422 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -1,5 +1,4 @@ using System.Text; -using System.Text.Json.Serialization; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.IdentityModel.Tokens; @@ -14,6 +13,7 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; using Volo.Abp.Swashbuckle; using Yi.Abp.Application; using Yi.Abp.SqlsugarCore; @@ -107,6 +107,12 @@ namespace Yi.Abp.Web }); }); + //配置多租户 + Configure(options => + { + //基于cookie jwt不好用,有坑 + options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName); + }); //jwt鉴权 var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get();