diff --git a/aspnet-core/LINGYUN.MicroService.sln b/aspnet-core/LINGYUN.MicroService.sln index af232f52f..bf559bea3 100644 --- a/aspnet-core/LINGYUN.MicroService.sln +++ b/aspnet-core/LINGYUN.MicroService.sln @@ -209,9 +209,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.IdentityServer. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.IdentityServer.EntityFrameworkCore", "modules\identityServer\LINGYUN.Abp.IdentityServer.EntityFrameworkCore\LINGYUN.Abp.IdentityServer.EntityFrameworkCore.csproj", "{5D0ED1FC-3A7C-4531-9512-832E73AD9555}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Identity.Domain", "modules\identity\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj", "{2BF7FB73-0C62-4ECF-99F0-0583855D2777}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.Domain", "modules\identity\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj", "{2BF7FB73-0C62-4ECF-99F0-0583855D2777}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Identity.EntityFrameworkCore", "modules\identity\LINGYUN.Abp.Identity.EntityFrameworkCore\LINGYUN.Abp.Identity.EntityFrameworkCore.csproj", "{6FE7E243-2D99-4567-8786-6C9283D608EF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.EntityFrameworkCore", "modules\identity\LINGYUN.Abp.Identity.EntityFrameworkCore\LINGYUN.Abp.Identity.EntityFrameworkCore.csproj", "{6FE7E243-2D99-4567-8786-6C9283D608EF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Domain.Entities.Events", "modules\common\LINGYUN.Abp.Domain.Entities.Events\LINGYUN.Abp.Domain.Entities.Events.csproj", "{AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -567,6 +569,10 @@ Global {6FE7E243-2D99-4567-8786-6C9283D608EF}.Debug|Any CPU.Build.0 = Debug|Any CPU {6FE7E243-2D99-4567-8786-6C9283D608EF}.Release|Any CPU.ActiveCfg = Release|Any CPU {6FE7E243-2D99-4567-8786-6C9283D608EF}.Release|Any CPU.Build.0 = Release|Any CPU + {AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -674,6 +680,7 @@ Global {5D0ED1FC-3A7C-4531-9512-832E73AD9555} = {0439B173-F41E-4CE0-A44A-CCB70328F272} {2BF7FB73-0C62-4ECF-99F0-0583855D2777} = {52B5D4F7-237B-4E0A-A167-68442164F70A} {6FE7E243-2D99-4567-8786-6C9283D608EF} = {52B5D4F7-237B-4E0A-A167-68442164F70A} + {AAD8EF65-1FBF-4F3F-8B33-8B76E1EBA4A5} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/configuration/account/AuthServer.Host/appsettings.Development.json b/aspnet-core/configuration/account/AuthServer.Host/appsettings.Development.json index aa82f1d34..171925d67 100644 --- a/aspnet-core/configuration/account/AuthServer.Host/appsettings.Development.json +++ b/aspnet-core/configuration/account/AuthServer.Host/appsettings.Development.json @@ -48,9 +48,10 @@ "VirtualHost": "multi.service.test" } }, - "RedisCache": { - "ConnectString": "127.0.0.1", - "RedisPrefix": "AuthServer" + "Redis": { + "Configuration": "127.0.0.1", + "InstanceName": "LINGYUN.AbpApplication", + "DefaultDatabase": 10 }, "AuthServer": { "Authority": "http://localhost:44385/", diff --git a/aspnet-core/configuration/admin/LINGYUN.BackendAdminApp.Host/appsettings.Development.json b/aspnet-core/configuration/admin/LINGYUN.BackendAdminApp.Host/appsettings.Development.json index 20218b346..a8d83e330 100644 --- a/aspnet-core/configuration/admin/LINGYUN.BackendAdminApp.Host/appsettings.Development.json +++ b/aspnet-core/configuration/admin/LINGYUN.BackendAdminApp.Host/appsettings.Development.json @@ -69,9 +69,10 @@ "VirtualHost": "Name of your RabbitMQ server VirtualHost" } }, - "RedisCache": { - "RedisPrefix": "Platform_Test_Cache", - "ConnectString": "127.0.0.1" + "Redis": { + "Configuration": "127.0.0.1", + "InstanceName": "LINGYUN.AbpApplication", + "DefaultDatabase": 10 }, "AuthServer": { "Authority": "http://localhost:44385/", diff --git a/aspnet-core/configuration/apigateway/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/apigateway/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json index e5e3214da..1542e3bb5 100644 --- a/aspnet-core/configuration/apigateway/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/configuration/apigateway/LINGYUN.ApiGateway.HttpApi.Host/appsettings.Development.json @@ -6,9 +6,10 @@ "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" }, - "RedisCache": { - "RedisPrefix": "ApiGateway_Test_Cache", - "ConnectString": "127.0.0.1" + "Redis": { + "Configuration": "127.0.0.1", + "InstanceName": "LINGYUN.AbpApplication", + "DefaultDatabase": 10 }, "CAP": { "EventBus": { diff --git a/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json index 74da04c9c..97b761933 100644 --- a/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json @@ -6,9 +6,10 @@ "AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" }, - "RedisCache": { - "RedisPrefix": "Platform_Test_Cache", - "ConnectString": "127.0.0.1" + "Redis": { + "Configuration": "127.0.0.1", + "InstanceName": "LINGYUN.AbpApplication", + "DefaultDatabase": 10 }, "AuthServer": { "Authority": "http://localhost:44385/", diff --git a/aspnet-core/configuration/platform/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/platform/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json index f2457af77..1df50d6b4 100644 --- a/aspnet-core/configuration/platform/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json +++ b/aspnet-core/configuration/platform/LINGYUN.Platform.HttpApi.Host/appsettings.Development.json @@ -22,9 +22,10 @@ "VirtualHost": "Name of your RabbitMQ server VirtualHost" } }, - "RedisCache": { - "RedisPrefix": "Platform_Test_Cache", - "ConnectString": "127.0.0.1" + "Redis": { + "Configuration": "127.0.0.1", + "InstanceName": "LINGYUN.AbpApplication", + "DefaultDatabase": 10 }, "AuthServer": { "Authority": "http://localhost:44385/", diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN.Abp.Domain.Entities.Events.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN.Abp.Domain.Entities.Events.csproj new file mode 100644 index 000000000..5949bdecb --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN.Abp.Domain.Entities.Events.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/AbpDddDomainEntitesEventsModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/AbpDddDomainEntitesEventsModule.cs new file mode 100644 index 000000000..1e58ef752 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/AbpDddDomainEntitesEventsModule.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Domain; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Domain.Entities.Events +{ + [DependsOn(typeof(AbpDddDomainModule))] + public class AbpDddDomainEntitesEventsModule : AbpModule + { + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/EntityChangeEventHelper.cs b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/EntityChangeEventHelper.cs new file mode 100644 index 000000000..69d29eee0 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Domain.Entities.Events/LINGYUN/Abp/Domain/Entites/Events/EntityChangeEventHelper.cs @@ -0,0 +1,151 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.DynamicProxy; +using Volo.Abp.EventBus; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.Domain.Entities.Events +{ + [Dependency(Microsoft.Extensions.DependencyInjection.ServiceLifetime.Transient, ReplaceServices = true)] + [ExposeServices(typeof(IEntityChangeEventHelper), typeof(Volo.Abp.Domain.Entities.Events.EntityChangeEventHelper))] + [Obsolete("the component will be removed when the abp framework is upgraded to 3.1.0")] + public class EntityChangeEventHelper : Volo.Abp.Domain.Entities.Events.EntityChangeEventHelper + { + public EntityChangeEventHelper( + IUnitOfWorkManager unitOfWorkManager, + IEntityToEtoMapper entityToEtoMapper, + IOptions distributedEntityEventOptions) + : base(unitOfWorkManager, entityToEtoMapper, distributedEntityEventOptions) + { + } + + protected override async Task TriggerEventWithEntity( + IEventBus eventPublisher, + Type genericEventType, + object entityOrEto, + object originalEntity, + bool triggerInCurrentUnitOfWork) + { + var entityType = ProxyHelper.UnProxy(entityOrEto).GetType(); + var eventType = genericEventType.MakeGenericType(entityType); + var currentUow = UnitOfWorkManager.Current; + + if (triggerInCurrentUnitOfWork || currentUow == null) + { + await eventPublisher.PublishAsync( + eventType, + Activator.CreateInstance(eventType, entityOrEto) + ); + + return; + } + + var eventList = GetEventList(currentUow); + var isFirstEvent = !eventList.Any(); + + eventList.AddUniqueEvent(eventPublisher, eventType, entityOrEto, originalEntity); + + /* Register to OnCompleted if this is the first item. + * Other items will already be in the list once the UOW completes. + */ + if (isFirstEvent) + { + currentUow.OnCompleted( + async () => + { + foreach (var eventEntry in eventList) + { + try + { + // TODO: abp.io 3.1修复 + await eventEntry.EventBus.PublishAsync( + eventEntry.EventType, + Activator.CreateInstance(eventEntry.EventType, eventEntry.EntityOrEto) + ); + } + catch (Exception ex) + { + Logger.LogError( + $"Caught an exception while publishing the event '{eventType.FullName}' for the entity '{entityOrEto}'"); + Logger.LogException(ex); + } + } + } + ); + } + } + + private EntityChangeEventList GetEventList(IUnitOfWork currentUow) + { + return (EntityChangeEventList)currentUow.Items.GetOrAdd( + "AbpEntityChangeEventList", + () => new EntityChangeEventList() + ); + } + + private class EntityChangeEventList : List + { + public void AddUniqueEvent(IEventBus eventBus, Type eventType, object entityOrEto, object originalEntity) + { + var newEntry = new EntityChangeEventEntry(eventBus, eventType, entityOrEto, originalEntity); + + //Latest "same" event overrides the previous events. + for (var i = 0; i < Count; i++) + { + if (this[i].IsSameEvent(newEntry)) + { + this[i] = newEntry; + return; + } + } + + //If this is a "new" event, add to the end + Add(newEntry); + } + } + + private class EntityChangeEventEntry + { + public IEventBus EventBus { get; } + + public Type EventType { get; } + + public object EntityOrEto { get; } + + public object OriginalEntity { get; } + + public EntityChangeEventEntry(IEventBus eventBus, Type eventType, object entityOrEto, object originalEntity) + { + EventType = eventType; + EntityOrEto = entityOrEto; + OriginalEntity = originalEntity; + EventBus = eventBus; + } + + public bool IsSameEvent(EntityChangeEventEntry otherEntry) + { + if (EventBus != otherEntry.EventBus || EventType != otherEntry.EventType) + { + return false; + } + + var originalEntityRef = OriginalEntity as IEntity; + var otherOriginalEntityRef = otherEntry.OriginalEntity as IEntity; + if (originalEntityRef == null || otherOriginalEntityRef == null) + { + return false; + } + + return EntityHelper.EntityEquals(originalEntityRef, otherOriginalEntityRef); + } + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs b/aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs index 3dd7f4fda..26c2a5c2a 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/Notifications/AbpNotificationsExceptionSubscriber.cs @@ -24,7 +24,15 @@ namespace LINGYUN.Abp.ExceptionHandling.Notifications var notificationDispatcher = context.ServiceProvider.GetRequiredService(); var notificationName = NotificationNameNormalizer .NormalizerName(AbpExceptionHandlingNotificationNames.NotificationName); - var notificationData = new NotificationData(); + NotificationData notificationData; + if (CurrentTenant.IsAvailable) + { + notificationData = NotificationData.CreateTenantNotificationData(CurrentTenant.Id.Value); + } + else + { + notificationData = NotificationData.CreateNotificationData(); + } // 写入通知数据 //TODO:集成TextTemplate完成格式化的推送 notificationData.WriteStandardData( diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs index 04c341cb6..f091ecf06 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs @@ -1,6 +1,5 @@ using LINGYUN.Abp.RealTime.Client; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; @@ -26,6 +25,11 @@ namespace LINGYUN.Abp.Notifications.SignalR IOnlineClient onlineClient = CreateClientForCurrentConnection(); Logger.LogDebug("A client is connected: " + onlineClient.ToString()); OnlineClientManager.Add(onlineClient); + if (onlineClient.TenantId.HasValue) + { + // 以租户为分组,将用户加入租户通讯组 + await Groups.AddToGroupAsync(onlineClient.ConnectionId, onlineClient.TenantId.Value.ToString()); + } } public override async Task OnDisconnectedAsync(Exception exception) diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs index 04afc41a8..0bfa29e70 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs @@ -30,31 +30,48 @@ namespace LINGYUN.Abp.Notifications.SignalR public override async Task PublishAsync(NotificationInfo notification, IEnumerable identifiers) { - // 返回标准数据给前端 - notification.Data = NotificationData.ToStandardData(notification.Data); - foreach (var identifier in identifiers) + if (notification.Data.HasTenantNotification(out Guid tenantId)) { - Logger.LogDebug($"Find online client with user {identifier.UserId} - {identifier.UserName}"); - var onlineClientContext = new OnlineClientContext(notification.TenantId, identifier.UserId); - var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); - foreach (var onlineClient in onlineClients) + // 返回标准数据给前端 + notification.Data = NotificationData.ToStandardData(notification.Data); + var singalRGroup = _hubContext.Clients.Group(tenantId.ToString()); + if (singalRGroup == null) { - try + Logger.LogDebug("Can not get group " + tenantId + " from SignalR hub!"); + return; + } + // 租户通知群发 + Logger.LogDebug($"Found a singalr group, begin senging notifications"); + await singalRGroup.SendAsync("getNotification", notification); + } + else + { + // 返回标准数据给前端 + notification.Data = NotificationData.ToStandardData(notification.Data); + foreach (var identifier in identifiers) + { + Logger.LogDebug($"Find online client with user {identifier.UserId} - {identifier.UserName}"); + var onlineClientContext = new OnlineClientContext(notification.TenantId, identifier.UserId); + var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); + foreach (var onlineClient in onlineClients) { - Logger.LogDebug($"Find online client {onlineClient.UserId} - {onlineClient.ConnectionId}"); - var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); - if (signalRClient == null) + try { - Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); - continue; + Logger.LogDebug($"Find online client {onlineClient.UserId} - {onlineClient.ConnectionId}"); + var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); + if (signalRClient == null) + { + Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); + continue; + } + Logger.LogDebug($"Found a singalr client, begin senging notifications"); + await signalRClient.SendAsync("getNotification", notification); + } + catch (Exception ex) + { + Logger.LogWarning("Could not send notifications to user: {0}", identifier.UserId); + Logger.LogWarning("Send to user notifications error: {0}", ex.Message); } - Logger.LogDebug($"Found a singalr client, begin senging notifications"); - await signalRClient.SendAsync("getNotification", notification); - } - catch (Exception ex) - { - Logger.LogWarning("Could not send notifications to user: {0}", identifier.UserId); - Logger.LogWarning("Send to user notifications error: {0}", ex.Message); } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs index ea6e40578..c9955adba 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationData.cs @@ -5,6 +5,10 @@ namespace LINGYUN.Abp.Notifications { public class NotificationData { + public const string NotificationKey = "N:G"; + public const string UserIdNotificationKey = "N:UI"; + public const string UserNameNotificationKey = "N:UN"; + public const string TenantNotificationKey = "N:T"; public virtual string Type => GetType().FullName; public object this[string key] @@ -45,6 +49,29 @@ namespace LINGYUN.Abp.Notifications { _properties = new Dictionary(); } + + public static NotificationData CreateNotificationData() + { + var data = new NotificationData(); + data.TrySetData(NotificationKey, "AbpNotification"); + return data; + } + + public static NotificationData CreateUserNotificationData(Guid userId, string userName) + { + var data = new NotificationData(); + data.TrySetData(UserIdNotificationKey, userId); + data.TrySetData(UserNameNotificationKey, userName); + return data; + } + + public static NotificationData CreateTenantNotificationData(Guid tenantId) + { + var data = new NotificationData(); + data.TrySetData(TenantNotificationKey, tenantId); + return data; + } + /// /// 写入标准数据 /// @@ -123,5 +150,28 @@ namespace LINGYUN.Abp.Notifications Properties[key] = value; } } + + public bool HasUserNotification(out Guid userId, out string userName) + { + if (Properties.TryGetValue(UserIdNotificationKey, out object userKey)) + { + userId = (Guid)userKey; + var name = TryGetData(UserNameNotificationKey); + userName = name != null ? name.ToString() : ""; + return true; + } + userName = ""; + return false; + } + + public bool HasTenantNotification(out Guid tenantId) + { + if (Properties.TryGetValue(TenantNotificationKey, out object tenantKey)) + { + tenantId = (Guid)tenantKey; + return true; + } + return false; + } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs index f585fbafb..3a0c8f3c5 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs @@ -9,6 +9,11 @@ using Volo.Abp.Localization; * 而是规范通知的一些属性,因此不应该是自定义通知名称,而是定义通知的类目,类似于Catalog * 或者Prefix * + * TODO: 2020-08-26 如果需要用户或者租户特定的消息该如何来发送通知? + * 是否追加字段:通知类别(宿主、租户、用户、通用),主要可以在运行时判断发布消息的来源, + * 如果是用户通知(NotificationData[FormUser])则只会查询用户对于用户通知的订阅(用户互动:站内信、私信、好友请求、留言等),优先级最低 + * 租户通知(NotificationData[FormTenant])则只会查询用户对于租户通知的订阅(系统发布、应用通知),优先级次于用户 + * 全局通知(NotificationData[FormGlobal])则查询用户对于全局通知的订阅(一般用于系统发布、应用通知),优先级最高 */ namespace LINGYUN.Abp.Notifications diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs index ce5db6c6c..f13b34542 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationType.cs @@ -6,12 +6,16 @@ public enum NotificationType { /// - /// 应用 + /// 应用(对应租户) /// Application = 0, /// - /// 系统 + /// 系统(对应宿主) /// - System = 10 + System = 10, + /// + /// 用户(对应用户) + /// + User = 20 } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs index 672f1cb08..d2b53d23a 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/Local/UserCreateSendWelcomeEventHandler.cs @@ -61,7 +61,7 @@ namespace LINGYUN.Abp.MessageService.EventBus //await _notificationStore.InsertUserSubscriptionAsync(eventData.Entity.TenantId, // userIdentifer, UserNotificationNames.WelcomeToApplication); - var userWelcomeNotifictionData = new NotificationData(); + var userWelcomeNotifictionData = NotificationData.CreateUserNotificationData(eventData.Entity.Id, eventData.Entity.UserName); userWelcomeNotifictionData.WriteStandardData( L("WelcomeToApplicationFormUser", eventData.Entity.Name ?? eventData.Entity.UserName), diff --git a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantCreateEventHandler.cs b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantCreateEventHandler.cs index aeeeb16a6..c207ab918 100644 --- a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantCreateEventHandler.cs +++ b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantCreateEventHandler.cs @@ -6,29 +6,30 @@ using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.TenantManagement; +using Volo.Abp.Uow; namespace LINGYUN.Abp.MultiTenancy.DbFinder.EventBus.Distributed { public class TenantCreateEventHandler : IDistributedEventHandler>, ITransientDependency { - private readonly IDataFilter _dataFilter; + private readonly ICurrentTenant _currentTenant; private readonly ITenantRepository _tenantRepository; private readonly IDistributedCache _cache; public TenantCreateEventHandler( - IDataFilter dataFilter, + ICurrentTenant currentTenant, ITenantRepository tenantRepository, IDistributedCache cache) { _cache = cache; - _dataFilter = dataFilter; + _currentTenant = currentTenant; _tenantRepository = tenantRepository; } + [UnitOfWork] public virtual async Task HandleEventAsync(EntityCreatedEto eventData) { - // 禁用租户过滤器 - using (_dataFilter.Disable()) + using (_currentTenant.Change(null)) { var tenant = await _tenantRepository.FindAsync(eventData.Entity.Id, true); if (tenant == null) diff --git a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantUpdateEventHandler.cs b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantUpdateEventHandler.cs index 2d0c597a2..4fe9dd599 100644 --- a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantUpdateEventHandler.cs +++ b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/EventBus/Distributed/TenantUpdateEventHandler.cs @@ -6,29 +6,30 @@ using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.TenantManagement; +using Volo.Abp.Uow; namespace LINGYUN.Abp.MultiTenancy.DbFinder.EventBus.Distributed { public class TenantUpdateEventHandler : IDistributedEventHandler>, ITransientDependency { - private readonly IDataFilter _dataFilter; + private readonly ICurrentTenant _currentTenant; private readonly ITenantRepository _tenantRepository; private readonly IDistributedCache _cache; public TenantUpdateEventHandler( - IDataFilter dataFilter, + ICurrentTenant currentTenant, ITenantRepository tenantRepository, IDistributedCache cache) { _cache = cache; - _dataFilter = dataFilter; + _currentTenant = currentTenant; _tenantRepository = tenantRepository; } + [UnitOfWork] public virtual async Task HandleEventAsync(EntityUpdatedEto eventData) { - // 禁用租户过滤器 - using (_dataFilter.Disable()) + using (_currentTenant.Change(null)) { var tenant = await _tenantRepository.FindAsync(eventData.Entity.Id, true); if (tenant == null) diff --git a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/TenantStore.cs b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/TenantStore.cs index b42114d7c..f3979f5f5 100644 --- a/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/TenantStore.cs +++ b/aspnet-core/modules/tenants/LINGYUN.Abp.MultiTenancy.DbFinder/LINGYUN/Abp/MultiTenancy/DbFinder/TenantStore.cs @@ -19,16 +19,16 @@ namespace LINGYUN.Abp.MultiTenancy.DbFinder { public ILogger Logger { protected get; set; } private readonly IDistributedCache _cache; - private readonly IDataFilter _dataFilter; + private readonly ICurrentTenant _currentTenant; private readonly ITenantRepository _tenantRepository; public TenantStore( - IDataFilter dataFilter, + ICurrentTenant currentTenant, ITenantRepository tenantRepository, IDistributedCache cache) { _cache = cache; - _dataFilter = dataFilter; + _currentTenant = currentTenant; _tenantRepository = tenantRepository; Logger = NullLogger.Instance; @@ -91,8 +91,7 @@ namespace LINGYUN.Abp.MultiTenancy.DbFinder } Logger.LogDebug($"Not found in the cache, getting from the repository: {cacheKey}"); - // 禁用租户过滤器 - using (_dataFilter.Disable()) + using (_currentTenant.Change(null)) { var tenant = await _tenantRepository.FindAsync(id, true); if (tenant == null) @@ -129,7 +128,7 @@ namespace LINGYUN.Abp.MultiTenancy.DbFinder } Logger.LogDebug($"Not found in the cache, getting from the repository: {cacheKey}"); - using (_dataFilter.Disable()) + using (_currentTenant.Change(null)) { var tenant = await _tenantRepository.FindByNameAsync(name); if (tenant == null) diff --git a/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs b/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs index 6c40eb4c7..9772d2bde 100644 --- a/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs +++ b/aspnet-core/modules/tenants/LINGYUN.Abp.TenantManagement.Application/LINGYUN/Abp/TenantManagement/TenantAppService.cs @@ -146,7 +146,16 @@ namespace LINGYUN.Abp.TenantManagement { var tenant = await TenantRepository.GetAsync(id); tenant.SetConnectionString(tenantConnectionStringCreateOrUpdate.Name, tenantConnectionStringCreateOrUpdate.Value); - + var updateEventData = new UpdateEventData + { + Id = tenant.Id, + OriginName = tenant.Name, + Name = tenant.Name + }; + // abp当前版本(3.0.0)在EntityChangeEventHelper中存在一个问题,无法发送框架默认的Eto,预计3.1.0修复 + // 发送自定义的事件数据来确保缓存被更新 + await EventBus.PublishAsync(updateEventData); + return new TenantConnectionStringDto { Name = tenantConnectionStringCreateOrUpdate.Name, @@ -160,6 +169,15 @@ namespace LINGYUN.Abp.TenantManagement var tenant = await TenantRepository.GetAsync(tenantConnectionGetByName.Id); tenant.RemoveConnectionString(tenantConnectionGetByName.Name); + + var updateEventData = new UpdateEventData + { + Id = tenant.Id, + OriginName = tenant.Name, + Name = tenant.Name + }; + await EventBus.PublishAsync(updateEventData); + await TenantRepository.UpdateAsync(tenant); } } diff --git a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs index baffec853..543961a9c 100644 --- a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs +++ b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs @@ -1,10 +1,13 @@ using DotNetCore.CAP; +using LINGYUN.Abp.Domain.Entities.Events; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.IdentityServer; +using LINGYUN.Abp.MultiTenancy.DbFinder; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -17,6 +20,7 @@ using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.MySQL; @@ -39,6 +43,9 @@ namespace AuthServer.Host typeof(AbpAutofacModule), typeof(AbpCAPEventBusModule), typeof(AbpIdentityAspNetCoreModule), + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpDddDomainEntitesEventsModule), + typeof(AbpCachingStackExchangeRedisModule), typeof(AbpIdentityServerSmsValidatorModule), typeof(AbpIdentityServerWeChatValidatorModule), typeof(AbpEntityFrameworkCoreMySQLModule), @@ -88,13 +95,27 @@ namespace AuthServer.Host Configure(options => { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; // 滑动过期30天 options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); // 绝对过期60天 - options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60); options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); }); + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + // 单独一个缓存数据库 + var databaseConfig = configuration.GetSection("Redis:DefaultDatabase"); + if (databaseConfig.Exists()) + { + redisConfig.DefaultDatabase = databaseConfig.Get(); + } + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + Configure(options => { options.Languages.Add(new LanguageInfo("en", "en", "English")); @@ -121,13 +142,6 @@ namespace AuthServer.Host options.IsEnabled = true; }); - context.Services.AddStackExchangeRedisCache(options => - { - options.Configuration = configuration["RedisCache:ConnectString"]; - var instanceName = configuration["RedisCache:RedisPrefix"]; - options.InstanceName = instanceName.IsNullOrEmpty() ? "MessageService_Cache" : instanceName; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj index fb3b42540..8b53e7a06 100644 --- a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj +++ b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj @@ -15,12 +15,12 @@ - - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -33,9 +33,11 @@ + + diff --git a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs index dcb6e577c..99abb0a3b 100644 --- a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs +++ b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs @@ -1,11 +1,13 @@ using DotNetCore.CAP; using IdentityModel; +using LINGYUN.Abp.Domain.Entities.Events; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.FileManagement; using LINGYUN.Abp.Location.Tencent; using LINGYUN.Abp.MessageService; +using LINGYUN.Abp.MultiTenancy.DbFinder; using LINGYUN.Abp.SettingManagement; using LINGYUN.Abp.TenantManagement; using LINGYUN.ApiGateway; @@ -16,6 +18,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -31,10 +34,10 @@ using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Autofac; using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.MySQL; -using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.Identity.Localization; using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.Localization; @@ -87,6 +90,9 @@ namespace LINGYUN.BackendAdmin typeof(AbpCAPEventBusModule), typeof(AbpAliyunSmsModule), typeof(AbpTencentLocationModule), + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpDddDomainEntitesEventsModule), typeof(AbpAutofacModule) )] public class BackendAdminHostModule : AbpModule @@ -158,12 +164,27 @@ namespace LINGYUN.BackendAdmin Configure(options => { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; // 滑动过期30天 options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); // 绝对过期60天 options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); }); + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + // 单独一个缓存数据库 + var databaseConfig = configuration.GetSection("Redis:DefaultDatabase"); + if (databaseConfig.Exists()) + { + redisConfig.DefaultDatabase = databaseConfig.Get(); + } + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + Configure(options => { options.FileSets.AddEmbedded("LINGYUN.BackendAdmin"); @@ -222,13 +243,6 @@ namespace LINGYUN.BackendAdmin AbpClaimTypes.Email = JwtClaimTypes.Email; }); - context.Services.AddStackExchangeRedisCache(options => - { - options.Configuration = configuration["RedisCache:ConnectString"]; - var instanceName = configuration["RedisCache:RedisPrefix"]; - options.InstanceName = instanceName.IsNullOrEmpty() ? "BackendAdmin_Cache" : instanceName; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/LINGYUN.BackendAdminApp.Host.csproj b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/LINGYUN.BackendAdminApp.Host.csproj index b68c8b473..cda240fd0 100644 --- a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/LINGYUN.BackendAdminApp.Host.csproj +++ b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/LINGYUN.BackendAdminApp.Host.csproj @@ -26,12 +26,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -40,6 +39,7 @@ + @@ -60,6 +60,7 @@ + @@ -75,6 +76,7 @@ + diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs index 6006e0251..991272cb8 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs @@ -1,12 +1,15 @@ using DotNetCore.CAP; using DotNetCore.CAP.Messages; using IdentityModel; +using LINGYUN.Abp.Domain.Entities.Events; using LINGYUN.Abp.EventBus.CAP; +using LINGYUN.Abp.MultiTenancy.DbFinder; using LINGYUN.ApiGateway.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -18,6 +21,8 @@ using System.Text; using Volo.Abp; using Volo.Abp.Autofac; using Volo.Abp.AutoMapper; +using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.MySQL; @@ -42,6 +47,9 @@ namespace LINGYUN.ApiGateway typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpCAPEventBusModule), + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpDddDomainEntitesEventsModule), typeof(AbpAutofacModule) )] public class ApiGatewayHttpApiHostModule : AbpModule @@ -79,6 +87,29 @@ namespace LINGYUN.ApiGateway options.DefaultSalt = Encoding.ASCII.GetBytes("sf&5)s3#"); }); + Configure(options => + { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(60); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + // 单独一个缓存数据库 + var databaseConfig = configuration.GetSection("Redis:DefaultDatabase"); + if (databaseConfig.Exists()) + { + redisConfig.DefaultDatabase = databaseConfig.Get(); + } + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + // 多租户 Configure(options => { @@ -119,13 +150,6 @@ namespace LINGYUN.ApiGateway AbpClaimTypes.Email = JwtClaimTypes.Email; }); - context.Services.AddStackExchangeRedisCache(options => - { - options.Configuration = configuration["RedisCache:ConnectString"]; - var instanceName = configuration["RedisCache:RedisPrefix"]; - options.InstanceName = instanceName.IsNullOrEmpty() ? "ApiGateway_Cache" : instanceName; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj index 2c4fb1915..e7b4803ec 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/LINGYUN.ApiGateway.HttpApi.Host.csproj @@ -11,15 +11,14 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -28,6 +27,7 @@ + @@ -39,7 +39,9 @@ + + diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs index a3ffed6e2..ec9408620 100644 --- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs @@ -39,6 +39,10 @@ namespace LINGYUN.Abp.MessageService.EventBus.Distributed /// protected INotificationStore NotificationStore { get; } /// + /// Reference to . + /// + protected INotificationSubscriptionManager NotificationSubscriptionManager { get; } + /// /// Reference to . /// protected INotificationPublishProviderManager NotificationPublishProviderManager { get; } @@ -50,11 +54,13 @@ namespace LINGYUN.Abp.MessageService.EventBus.Distributed IBackgroundJobManager backgroundJobManager, IOptions options, INotificationStore notificationStore, + INotificationSubscriptionManager notificationSubscriptionManager, INotificationPublishProviderManager notificationPublishProviderManager) { BackgroundJobManager = backgroundJobManager; Options = options.Value; NotificationStore = notificationStore; + NotificationSubscriptionManager = notificationSubscriptionManager; NotificationPublishProviderManager = notificationPublishProviderManager; Logger = NullLogger.Instance; @@ -85,9 +91,16 @@ namespace LINGYUN.Abp.MessageService.EventBus.Distributed // 持久化通知 await NotificationStore.InsertNotificationAsync(notificationInfo); + // TODO: 某些情况下,不能直接在服务内订阅消息,目前只能通过将订阅内容放进消息内部,需要重构通知系统设计了 + if (notificationInfo.Data.HasUserNotification(out Guid userId, out string userName)) + { + await NotificationSubscriptionManager.SubscribeAsync(notificationInfo.TenantId, + new UserIdentifier(userId, userName), notificationInfo.Name); + } + Logger.LogDebug($"Gets a list of user subscriptions {notificationInfo.Name}"); // 获取用户订阅列表 - var userSubscriptions = await NotificationStore.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name); + var userSubscriptions = await NotificationSubscriptionManager.GetSubscriptionsAsync(notificationInfo.TenantId, notificationInfo.Name); Logger.LogDebug($"Persistent user notifications {notificationInfo.Name}"); // 持久化用户通知 diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs index 9053a16e9..f7aeb94ec 100644 --- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/TenantCreateEventHandler.cs @@ -55,7 +55,7 @@ namespace LINGYUN.Abp.MessageService.EventBus.Distributed // 管理用户订阅租户创建通知 await NotificationSubscriptionManager.SubscribeAsync(eventData.Id, tenantAdminUserIdentifier, noticeNormalizerName.Name); - var notificationData = new NotificationData(); + var notificationData = NotificationData.CreateTenantNotificationData(eventData.Id); notificationData.WriteStandardData( L("NewTenantRegisteredNotificationTitle"), L("NewTenantRegisteredNotificationMessage", eventData.Name), diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj index a70f01c71..7f323bee6 100644 --- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj @@ -19,12 +19,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -33,6 +32,7 @@ + @@ -43,6 +43,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs index 8a4b61c99..4b7729474 100644 --- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs +++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs @@ -2,6 +2,7 @@ using Hangfire; using IdentityModel; using LINGYUN.Abp.BackgroundJobs.Hangfire; +using LINGYUN.Abp.Domain.Entities.Events; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Notifications; @@ -10,11 +11,13 @@ using LINGYUN.Abp.IM.SignalR; using LINGYUN.Abp.MessageService.EntityFrameworkCore; using LINGYUN.Abp.MessageService.Localization; using LINGYUN.Abp.MessageService.MultiTenancy; +using LINGYUN.Abp.MultiTenancy.DbFinder; using LINGYUN.Abp.Notifications.SignalR; using LINGYUN.Abp.Notifications.WeChat.WeApp; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -27,6 +30,7 @@ using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.Autofac; using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -56,6 +60,9 @@ namespace LINGYUN.Abp.MessageService typeof(AbpCAPEventBusModule), typeof(AbpBackgroundJobsHangfireModule), typeof(AbpHangfireMySqlStorageModule), + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpDddDomainEntitesEventsModule), typeof(AbpAutofacModule) )] public class AbpMessageServiceHttpApiHostModule : AbpModule @@ -124,6 +131,29 @@ namespace LINGYUN.Abp.MessageService options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor()); }); + Configure(options => + { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + // 单独一个缓存数据库 + var databaseConfig = configuration.GetSection("Redis:DefaultDatabase"); + if (databaseConfig.Exists()) + { + redisConfig.DefaultDatabase = databaseConfig.Get(); + } + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + // Swagger context.Services.AddSwaggerGen( options => @@ -156,13 +186,6 @@ namespace LINGYUN.Abp.MessageService AbpClaimTypes.Email = JwtClaimTypes.Email; }); - context.Services.AddStackExchangeRedisCache(options => - { - options.Configuration = configuration["RedisCache:ConnectString"]; - var instanceName = configuration["RedisCache:RedisPrefix"]; - options.InstanceName = instanceName.IsNullOrEmpty() ? "MessageService_Cache" : instanceName; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs index f1a4587ff..1a23b6508 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/AppPlatformHttpApiHostModule.cs @@ -1,9 +1,11 @@ using DotNetCore.CAP; using IdentityModel; +using LINGYUN.Abp.Domain.Entities.Events; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling; using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.FileManagement; +using LINGYUN.Abp.MultiTenancy.DbFinder; using LINGYUN.Abp.Notifications; using LINGYUN.Platform.EntityFrameworkCore; using LINGYUN.Platform.HttpApi; @@ -12,6 +14,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -27,6 +30,7 @@ using Volo.Abp.Autofac; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.FileSystem; using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -55,6 +59,9 @@ namespace LINGYUN.Platform typeof(AbpEmailingExceptionHandlingModule), typeof(AbpCAPEventBusModule), typeof(AbpBlobStoringFileSystemModule), + typeof(AbpDbFinderMultiTenancyModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpDddDomainEntitesEventsModule), typeof(AbpAutofacModule) )] public class AppPlatformHttpApiHostModule : AbpModule @@ -129,12 +136,27 @@ namespace LINGYUN.Platform Configure(options => { + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; // 滑动过期30天 options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30); // 绝对过期60天 options.GlobalCacheEntryOptions.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60); }); + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + // 单独一个缓存数据库 + var databaseConfig = configuration.GetSection("Redis:DefaultDatabase"); + if (databaseConfig.Exists()) + { + redisConfig.DefaultDatabase = databaseConfig.Get(); + } + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + Configure(options => { options.FileSets.AddEmbedded("LINGYUN.Platform"); @@ -190,13 +212,6 @@ namespace LINGYUN.Platform AbpClaimTypes.Email = JwtClaimTypes.Email; }); - context.Services.AddStackExchangeRedisCache(options => - { - options.Configuration = configuration["RedisCache:ConnectString"]; - var instanceName = configuration["RedisCache:RedisPrefix"]; - options.InstanceName = instanceName.IsNullOrEmpty() ? "Platform_Cache" : instanceName; - }); - if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); diff --git a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj index ac8e55757..00aa72acf 100644 --- a/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj +++ b/aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj @@ -21,12 +21,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -35,6 +34,7 @@ + @@ -46,6 +46,7 @@ + @@ -54,6 +55,7 @@ +