From f2e3c765393f8a7d5b7096e52881f7cfddbf71f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Sat, 18 May 2024 03:06:53 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=A4=9A?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=B8=8A=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DbConnOptions.cs | 61 --------------- ...bute.cs => DefaultTenantTableAttribute.cs} | 2 +- .../SqlSugarDbContext.cs | 20 ++--- .../TenantService.cs | 19 ++++- .../SqlSugarTenantStore.cs | 18 +---- .../TenantAggregateRoot.cs | 2 +- .../TenantManagementExtensions.cs | 10 +-- .../YiMultiTenantConnectionStringResolver.cs | 18 +++-- .../YiTenantConfigurationProvider.cs | 74 +++++++++++++++++++ Yi.Abp.Net8/src/Yi.Abp.Web/TestOptions.cs | 30 ++++++++ Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs | 7 ++ 11 files changed, 154 insertions(+), 107 deletions(-) rename Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/{MasterTenantAttribute.cs => DefaultTenantTableAttribute.cs} (80%) create mode 100644 Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiTenantConfigurationProvider.cs create mode 100644 Yi.Abp.Net8/src/Yi.Abp.Web/TestOptions.cs diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs index 8ad3c5d4..0d2e1345 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs @@ -51,66 +51,5 @@ namespace Yi.Framework.SqlSugarCore.Abstractions /// public bool EnabledSaasMultiTenancy { get; set; } = false; - - /// - /// 默认租户库连接,如果不填,那就是默认库的地址 - /// - public string? MasterSaasMultiTenancyUrl { get; set; } - - - /// - /// Saas租户连接 - /// - public List? SaasMultiTenancy { get; set; } - - public static string MasterTenantName = "Master"; - public static string DefaultTenantName = "Default"; - - /// - /// 获取默认数据库 - /// - /// - public SaasMultiTenancyOptions GetDefaultSaasMultiTenancy() - { - return new SaasMultiTenancyOptions { Name = DefaultTenantName, Url = Url }; - } - - /// - /// 获取主数据库 - /// - /// - public SaasMultiTenancyOptions? GetMasterSaasMultiTenancy() - { - if (EnabledSaasMultiTenancy == false) - { - return null; - } - if (string.IsNullOrEmpty(MasterSaasMultiTenancyUrl)) - { - - return new SaasMultiTenancyOptions { Name = MasterTenantName, Url = Url }; - } - else - { - return new SaasMultiTenancyOptions() - { - Name = MasterTenantName, - 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/MasterTenantAttribute.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs similarity index 80% rename from Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/MasterTenantAttribute.cs rename to Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs index fee1dee7..2b2519ef 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/MasterTenantAttribute.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DefaultTenantTableAttribute.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Yi.Framework.SqlSugarCore.Abstractions { [AttributeUsage(AttributeTargets.Class)] - public class MasterTenantAttribute : Attribute + public class DefaultTenantTableAttribute : Attribute { } } diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs index e99d7da2..ef40f34e 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs @@ -25,7 +25,6 @@ namespace Yi.Framework.SqlSugarCore /// public ISqlSugarClient SqlSugarClient { get; private set; } public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService(); - private readonly string MasterTenantDbDefaultName = DbConnOptions.MasterTenantName; private IAbpLazyServiceProvider LazyServiceProvider { get; } private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService(); @@ -38,6 +37,7 @@ namespace Yi.Framework.SqlSugarCore public IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService(NullEntityChangeEventHelper.Instance); public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService>().Value; + public AbpDbConnectionOptions ConnectionOptions=> LazyServiceProvider.LazyGetRequiredService>().Value; private ISqlSugarDbConnectionCreator _dbConnectionCreator; public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient) @@ -69,21 +69,23 @@ namespace Yi.Framework.SqlSugarCore /// protected virtual string GetCurrentConnectionString() { + var defautlUrl = Options.Url ?? ConnectionOptions.GetConnectionStringOrNull(ConnectionStrings.DefaultConnectionStringName); + //如果未开启多租户,返回db url 或者 默认连接字符串 + if (!Options.EnabledSaasMultiTenancy) + { + return defautlUrl; + } + + //开启了多租户 var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService(); var connectionString = connectionStringResolver.ResolveAsync().Result; + //没有检测到使用多租户功能,默认使用默认库即可 if (string.IsNullOrWhiteSpace(connectionString)) { Volo.Abp.Check.NotNull(Options.Url, "租户默认库Defalut未找到"); - connectionString = Options.Url; - } - //如果当前租户是主库,单独使用主要库 - if (CurrentTenant.Name == MasterTenantDbDefaultName) - { - var conStrOrNull = Options.GetMasterSaasMultiTenancy(); - Volo.Abp.Check.NotNull(conStrOrNull, "租户主库Master未找到"); - connectionString = conStrOrNull.Url; + connectionString = defautlUrl; } return connectionString!; } diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Application/TenantService.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Application/TenantService.cs index c5477371..11979e9f 100644 --- a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Application/TenantService.cs +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Application/TenantService.cs @@ -6,6 +6,7 @@ using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Data; using Volo.Abp.Modularity; +using Volo.Abp.Uow; using Yi.Framework.Ddd.Application; using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.TenantManagement.Application.Contracts; @@ -113,6 +114,7 @@ namespace Yi.Framework.TenantManagement.Application [HttpPut("tenant/init/{id}")] public async Task InitAsync([FromRoute] Guid id) { + await CurrentUnitOfWork.SaveChangesAsync(); using (CurrentTenant.Change(id)) { await CodeFirst(this.LazyServiceProvider); @@ -124,10 +126,20 @@ namespace Yi.Framework.TenantManagement.Application private async Task CodeFirst(IServiceProvider service) { var moduleContainer = service.GetRequiredService(); - var db = await _repository.GetDbContextAsync(); - //尝试创建数据库 - db.DbMaintenance.CreateDatabase(); + //没有数据库,不能创工作单元,创建库,先关闭 + ISqlSugarClient db = null; + using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: false)) + { + db = await _repository.GetDbContextAsync(); + //尝试创建数据库 + db.DbMaintenance.CreateDatabase(); + await uow.CompleteAsync(); + } + + + + List types = new List(); foreach (var module in moduleContainer.Modules) @@ -135,6 +147,7 @@ namespace Yi.Framework.TenantManagement.Application types.AddRange(module.Assembly.GetTypes() .Where(x => x.GetCustomAttribute() == null) .Where(x => x.GetCustomAttribute() != null) + .Where(x=>x.GetCustomAttribute() is 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 684be613..34750ce5 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 @@ -93,24 +93,8 @@ namespace Yi.Framework.TenantManagement.Domain private ConnectionStrings? MaptoString(string tenantConnectionString) { - - //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; - //} - connectionStrings["test"] = tenantConnectionString; - + connectionStrings[ConnectionStrings.DefaultConnectionStringName] = 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 55bfbc00..7f0424c3 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 @@ -10,7 +10,7 @@ using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.TenantManagement.Domain { [SugarTable("YiTenant")] - [MasterTenant] + [DefaultTenantTable] public class TenantAggregateRoot : FullAuditedAggregateRoot, IHasEntityVersion { public TenantAggregateRoot() 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 index dbe47fa1..9b2ee8ae 100644 --- 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 @@ -1,18 +1,14 @@ -using Volo.Abp.MultiTenancy; +using Volo.Abp.Data; +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.MasterTenantName); - } - public static IDisposable ChangeDefalut(this ICurrentTenant currentTenant) { - return currentTenant.Change(null, DbConnOptions.DefaultTenantName); + return currentTenant.Change(null, ConnectionStrings.DefaultConnectionStringName); } } } diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiMultiTenantConnectionStringResolver.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiMultiTenantConnectionStringResolver.cs index 503c3966..6da0fd34 100644 --- a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiMultiTenantConnectionStringResolver.cs +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiMultiTenantConnectionStringResolver.cs @@ -44,14 +44,16 @@ public class YiMultiTenantConnectionStringResolver : DefaultConnectionStringReso 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!; - //} + 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?.FirstOrDefault().Value; diff --git a/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiTenantConfigurationProvider.cs b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiTenantConfigurationProvider.cs new file mode 100644 index 00000000..0914e47c --- /dev/null +++ b/Yi.Abp.Net8/module/tenant-management/Yi.Framework.TenantManagement.Domain/YiTenantConfigurationProvider.cs @@ -0,0 +1,74 @@ +using Microsoft.Extensions.Localization; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy.Localization; + +namespace Volo.Abp.MultiTenancy; + +[Dependency(ReplaceServices =true)] +public class YiTenantConfigurationProvider : ITenantConfigurationProvider, ITransientDependency +{ + protected virtual ITenantResolver TenantResolver { get; } + protected virtual ITenantStore TenantStore { get; } + protected virtual ITenantResolveResultAccessor TenantResolveResultAccessor { get; } + protected virtual IStringLocalizer StringLocalizer { get; } + + public YiTenantConfigurationProvider( + ITenantResolver tenantResolver, + ITenantStore tenantStore, + ITenantResolveResultAccessor tenantResolveResultAccessor, + IStringLocalizer stringLocalizer) + { + TenantResolver = tenantResolver; + TenantStore = tenantStore; + TenantResolveResultAccessor = tenantResolveResultAccessor; + StringLocalizer = stringLocalizer; + } + + public virtual async Task GetAsync(bool saveResolveResult = false) + { + var resolveResult = await TenantResolver.ResolveTenantIdOrNameAsync(); + + if (saveResolveResult) + { + TenantResolveResultAccessor.Result = resolveResult; + } + + TenantConfiguration? tenant = null; + if (resolveResult.TenantIdOrName != null) + { + tenant = await FindTenantAsync(resolveResult.TenantIdOrName); + + if (tenant == null) + { + throw new BusinessException( + code: "Volo.AbpIo.MultiTenancy:010001", + message: StringLocalizer["TenantNotFoundMessage"], + details: StringLocalizer["TenantNotFoundDetails", resolveResult.TenantIdOrName] + ); + } + + if (!tenant.IsActive) + { + throw new BusinessException( + code: "Volo.AbpIo.MultiTenancy:010002", + message: StringLocalizer["TenantNotActiveMessage"], + details: StringLocalizer["TenantNotActiveDetails", resolveResult.TenantIdOrName] + ); + } + } + + return tenant; + } + + protected virtual async Task FindTenantAsync(string tenantIdOrName) + { + if (Guid.TryParse(tenantIdOrName, out var parsedTenantId)) + { + return await TenantStore.FindAsync(parsedTenantId); + } + else + { + return await TenantStore.FindAsync(tenantIdOrName); + } + } +} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/TestOptions.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/TestOptions.cs new file mode 100644 index 00000000..bbcce5d0 --- /dev/null +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/TestOptions.cs @@ -0,0 +1,30 @@ +using Volo.Abp.Data; + +namespace Yi.Abp.Web +{ + public class TestOptions + { + public ConnectionStrings2 ConnectionStrings { get; set; }=new ConnectionStrings2(); + + public AbpDatabaseInfoDictionary2 Databases { get; set; }=new AbpDatabaseInfoDictionary2(); + } + + public class ConnectionStrings2 : Dictionary + { + } + public class AbpDatabaseInfoDictionary2 : Dictionary + { + } + + public class AbpDatabaseInfo2 + { + internal AbpDatabaseInfo2(string databaseName) + { + DatabaseName = databaseName; + MappedConnections = new HashSet(); + } + public string DatabaseName { get; } + public HashSet MappedConnections { get; } + public bool IsUsedByTenants { get; set; } = true; + } +} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index 3d02c2ea..e6f33dec 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -15,6 +15,7 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.Caching; +using Volo.Abp.Data; using Volo.Abp.MultiTenancy; using Volo.Abp.Swashbuckle; using Yi.Abp.Application; @@ -249,6 +250,8 @@ namespace Yi.Abp.Web //授权 context.Services.AddAuthorization(); + + Configure(configuration); return Task.CompletedTask; } @@ -257,6 +260,10 @@ namespace Yi.Abp.Web { var service = context.ServiceProvider; + var sss=service.GetRequiredService>().Value; + + + var env = context.GetEnvironment(); var app = context.GetApplicationBuilder();