diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index efd7a4322..d69ed2ef4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,7 +2,7 @@ name: "Publish" on: push: - branches: [ rel-8.3.4 ] + branches: [ main ] env: DOTNET_VERSION: "8.0.200" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 697605b3b..c0e87a66a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: "Tagged Release" on: push: - branches: [ rel-8.3.4 ] + branches: [ main ] jobs: tagged-release: diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 1ed9cfe2b..5581b0989 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -767,6 +767,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OssManagement.I EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Notifications.HttpApi.Client", "modules\realtime-notifications\LINGYUN.Abp.Notifications.HttpApi.Client\LINGYUN.Abp.Notifications.HttpApi.Client.csproj", "{3CBD1342-C021-49FB-933F-FAC1DAFC7B48}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Notifications.Templating", "modules\realtime-notifications\LINGYUN.Abp.Notifications.Templating\LINGYUN.Abp.Notifications.Templating.csproj", "{E2AC3DB8-D579-49A3-845B-528C77A1EC75}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Notifications.Templating.Tests", "tests\LINGYUN.Abp.Notifications.Templating.Tests\LINGYUN.Abp.Notifications.Templating.Tests.csproj", "{F47EDB4F-1F92-4887-8F33-BFCEB61BB51A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1969,6 +1973,14 @@ Global {3CBD1342-C021-49FB-933F-FAC1DAFC7B48}.Debug|Any CPU.Build.0 = Debug|Any CPU {3CBD1342-C021-49FB-933F-FAC1DAFC7B48}.Release|Any CPU.ActiveCfg = Release|Any CPU {3CBD1342-C021-49FB-933F-FAC1DAFC7B48}.Release|Any CPU.Build.0 = Release|Any CPU + {E2AC3DB8-D579-49A3-845B-528C77A1EC75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2AC3DB8-D579-49A3-845B-528C77A1EC75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2AC3DB8-D579-49A3-845B-528C77A1EC75}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2AC3DB8-D579-49A3-845B-528C77A1EC75}.Release|Any CPU.Build.0 = Release|Any CPU + {F47EDB4F-1F92-4887-8F33-BFCEB61BB51A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F47EDB4F-1F92-4887-8F33-BFCEB61BB51A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F47EDB4F-1F92-4887-8F33-BFCEB61BB51A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F47EDB4F-1F92-4887-8F33-BFCEB61BB51A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2340,6 +2352,8 @@ Global {76DDE71D-00BD-4BC8-AEA2-31209E2B7E05} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6} {267933BD-BFB8-4906-BA39-DF193B2FD558} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6} {3CBD1342-C021-49FB-933F-FAC1DAFC7B48} = {1A23BB7F-1839-4204-88C5-7E9A6C9FBF1E} + {E2AC3DB8-D579-49A3-845B-528C77A1EC75} = {1A23BB7F-1839-4204-88C5-7E9A6C9FBF1E} + {F47EDB4F-1F92-4887-8F33-BFCEB61BB51A} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln index 7c62c9ff2..c0759b755 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln @@ -616,6 +616,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.AuditLogging.IP EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LY.MicroService.Applications.Single.EntityFrameworkCore.MySql", "migrations\LY.MicroService.Applications.Single.EntityFrameworkCore.MySql\LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.csproj", "{746813A9-4221-42D8-AAB5-66CB69EC844F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Notifications.Templating", "modules\realtime-notifications\LINGYUN.Abp.Notifications.Templating\LINGYUN.Abp.Notifications.Templating.csproj", "{8CFA17AA-568C-4B40-A48E-1212123ABDD6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1622,6 +1624,10 @@ Global {746813A9-4221-42D8-AAB5-66CB69EC844F}.Debug|Any CPU.Build.0 = Debug|Any CPU {746813A9-4221-42D8-AAB5-66CB69EC844F}.Release|Any CPU.ActiveCfg = Release|Any CPU {746813A9-4221-42D8-AAB5-66CB69EC844F}.Release|Any CPU.Build.0 = Release|Any CPU + {8CFA17AA-568C-4B40-A48E-1212123ABDD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CFA17AA-568C-4B40-A48E-1212123ABDD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CFA17AA-568C-4B40-A48E-1212123ABDD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CFA17AA-568C-4B40-A48E-1212123ABDD6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1921,6 +1927,7 @@ Global {5BE31786-EAAB-4C86-8FFF-C07F27FBFD1C} = {99B7CBDE-A251-4738-97F0-DB1DB484BEE1} {77B3C7A4-15C7-4EFF-8451-4F13B4CCA4AE} = {C22741F9-FC56-4AE3-B543-9F15C779D345} {746813A9-4221-42D8-AAB5-66CB69EC844F} = {0D69B63D-F082-4D57-9FF0-355642C56993} + {8CFA17AA-568C-4B40-A48E-1212123ABDD6} = {42F31C68-B8B2-4BE0-9AD0-A7DFA6092629} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xml b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xsd b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN.Abp.Notifications.Templating.csproj b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN.Abp.Notifications.Templating.csproj new file mode 100644 index 000000000..188573b06 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN.Abp.Notifications.Templating.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Notifications.Templating + LINGYUN.Abp.Notifications.Templating + false + false + false + + + + + + + + diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsResolveOptions.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsResolveOptions.cs new file mode 100644 index 000000000..8fde7a895 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsResolveOptions.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications.Templating; +public class AbpNotificationsResolveOptions +{ + /// + /// 模板解析提供者列表 + /// + [NotNull] + public List TemplateResolvers { get; } + + public AbpNotificationsResolveOptions() + { + TemplateResolvers = new List(); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingModule.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingModule.cs new file mode 100644 index 000000000..ddcabe3e9 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.Templating; + +[DependsOn(typeof(AbpNotificationsCoreModule))] +public class AbpNotificationsTemplatingModule : AbpModule +{ + +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContext.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContext.cs new file mode 100644 index 000000000..723f8a46c --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContext.cs @@ -0,0 +1,11 @@ +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications.Templating; +public interface INotificationTemplateResolveContext : IServiceProviderAccessor +{ + NotificationTemplate Template { get; } + + object Model { get; set; } + + bool Handled { get; set; } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContributor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContributor.cs new file mode 100644 index 000000000..9326eac5d --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolveContributor.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Templating; +public interface INotificationTemplateResolveContributor +{ + string Name { get; } + + Task ResolveAsync(INotificationTemplateResolveContext context); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolver.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolver.cs new file mode 100644 index 000000000..a88345afd --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/INotificationTemplateResolver.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Templating; +/// +/// 通知模板模型解析接口 +/// +public interface INotificationTemplateResolver +{ + /// + /// 解析模板数据 + /// + /// + /// + [NotNull] + Task ResolveAsync(NotificationTemplate template); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContext.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContext.cs new file mode 100644 index 000000000..1de28038b --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContext.cs @@ -0,0 +1,26 @@ +using System; + +namespace LINGYUN.Abp.Notifications.Templating; +public class NotificationTemplateResolveContext : INotificationTemplateResolveContext +{ + public IServiceProvider ServiceProvider { get; } + + public NotificationTemplate Template { get; } + + public object Model { get; set; } + + public bool Handled { get; set; } + + public bool HasResolvedModel() + { + return Handled || Model != null; + } + + public NotificationTemplateResolveContext( + NotificationTemplate template, + IServiceProvider serviceProvider) + { + Template = template; + ServiceProvider = serviceProvider; + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContributorBase.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContributorBase.cs new file mode 100644 index 000000000..6e1d55080 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveContributorBase.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Templating; +public abstract class NotificationTemplateResolveContributorBase : INotificationTemplateResolveContributor +{ + public abstract string Name { get; } + /// + /// 实现此接口处理模板数据 + /// + /// + /// + public abstract Task ResolveAsync(INotificationTemplateResolveContext context); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveResult.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveResult.cs new file mode 100644 index 000000000..c1cd21968 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolveResult.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications.Templating; +public class NotificationTemplateResolveResult +{ + /// + /// 模板数据 + /// + public object Model { get; set; } + + public List AppliedResolvers { get; } + public NotificationTemplateResolveResult() + { + AppliedResolvers = new List(); + } +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolver.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolver.cs new file mode 100644 index 000000000..b92d95044 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications.Templating/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolver.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Notifications.Templating; +public class NotificationTemplateResolver : INotificationTemplateResolver, ITransientDependency +{ + private readonly IServiceProvider _serviceProvider; + private readonly AbpNotificationsResolveOptions _options; + + public NotificationTemplateResolver( + IOptions options, + IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _options = options.Value; + } + public async virtual Task ResolveAsync(NotificationTemplate template) + { + var result = new NotificationTemplateResolveResult(); + + using (var serviceScope = _serviceProvider.CreateScope()) + { + var context = new NotificationTemplateResolveContext(template, serviceScope.ServiceProvider); + + foreach (var resolveContributor in _options.TemplateResolvers) + { + // TODO: 设定为每一个通知都配置自己的解析提供者? + /** + if (resolveContributor.Name.Equals(template.Name)) + { + await resolveContributor.ResolveAsync(context); + } + + if (context.HasResolvedModel()) + { + result.Model = context.Model; + break; + } + **/ + + await resolveContributor.ResolveAsync(context); + + result.AppliedResolvers.Add(resolveContributor.Name); + + if (context.HasResolvedModel()) + { + result.Model = context.Model; + break; + } + } + } + + return result; + } +} diff --git a/aspnet-core/services/Directory.Packages.props b/aspnet-core/services/Directory.Packages.props index 9c3dce1ab..cbce42789 100644 --- a/aspnet-core/services/Directory.Packages.props +++ b/aspnet-core/services/Directory.Packages.props @@ -3,53 +3,6 @@ 8.3.4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj b/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj index 0fbfdd223..61185e75c 100644 --- a/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj +++ b/aspnet-core/services/LY.AIO.Applications.Single/LY.AIO.Applications.Single.csproj @@ -1,4 +1,4 @@ - + @@ -54,6 +54,7 @@ + @@ -212,8 +213,6 @@ - - @@ -261,12 +260,4 @@ - - - - - - - - diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs index 8f9ee9a3e..5cc4b0e37 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/EventBus/Distributed/NotificationEventHandler.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications.Templating; using LY.MicroService.Applications.Single.BackgroundJobs; using LY.MicroService.Applications.Single.MultiTenancy; using Microsoft.Extensions.Localization; @@ -65,6 +66,10 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed /// protected IStringLocalizerFactory StringLocalizerFactory { get; } /// + /// Reference to . + /// + protected INotificationTemplateResolver NotificationTemplateResolver { get; } + /// /// Reference to . /// protected INotificationDataSerializer NotificationDataSerializer { get; } @@ -94,6 +99,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed IOptions options, INotificationStore notificationStore, INotificationDataSerializer notificationDataSerializer, + INotificationTemplateResolver notificationTemplateResolver, INotificationDefinitionManager notificationDefinitionManager, INotificationSubscriptionManager notificationSubscriptionManager, INotificationPublishProviderManager notificationPublishProviderManager) @@ -107,6 +113,7 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed StringLocalizerFactory = stringLocalizerFactory; NotificationStore = notificationStore; NotificationDataSerializer = notificationDataSerializer; + NotificationTemplateResolver = notificationTemplateResolver; NotificationDefinitionManager = notificationDefinitionManager; NotificationSubscriptionManager = notificationSubscriptionManager; NotificationPublishProviderManager = notificationPublishProviderManager; @@ -130,23 +137,25 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed } using (CultureHelper.Use(culture, culture)) { + var result = await NotificationTemplateResolver.ResolveAsync(eventData.Data); + if (notification.NotificationType == NotificationType.System) { using (CurrentTenant.Change(null)) { - await SendToTenantAsync(null, notification, eventData); + await SendToTenantAsync(null, notification, eventData, result); var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); foreach (var activeTenant in allActiveTenants) { - await SendToTenantAsync(activeTenant.Id, notification, eventData); + await SendToTenantAsync(activeTenant.Id, notification, eventData, result); } } } else { - await SendToTenantAsync(eventData.TenantId, notification, eventData); + await SendToTenantAsync(eventData.TenantId, notification, eventData, result); } } } @@ -183,7 +192,8 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed protected async virtual Task SendToTenantAsync( Guid? tenantId, NotificationDefinition notification, - NotificationEto eventData) + NotificationEto eventData, + NotificationTemplateResolveResult templateResolveResult) { using (CurrentTenant.Change(tenantId)) { @@ -219,7 +229,8 @@ namespace LY.MicroService.Applications.Single.EventBus.Distributed // 由于模板通知受租户影响, 格式化失败的消息将被丢弃. message = await TemplateRenderer.RenderAsync( templateName: eventData.Data.Name, - model: eventData.Data.ExtraProperties, + // 序列化之后数据可能需要自行处理, 如未处理数据, 将使用默认数据渲染模板 + model: templateResolveResult.Model ?? eventData.Data.ExtraProperties, cultureName: eventData.Data.Culture, globalContext: new Dictionary { diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index f19b3c14a..0581ca288 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -202,6 +202,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index 4abe4ef46..4d38ff881 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,6 +1,7 @@ using LINGYUN.Abp.AuditLogging.IP.Location; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.IP2Region; +using LINGYUN.Abp.Notifications.Templating; using LY.MicroService.Applications.Single.EntityFrameworkCore; using LY.MicroService.Applications.Single.EntityFrameworkCore.MySql; using Volo.Abp.MailKit; @@ -295,6 +296,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpNotificationsSignalRModule), // 通知模块 邮件通知 typeof(AbpNotificationsEmailingModule), + // 通知模块 模板解析 + typeof(AbpNotificationsTemplatingModule), // 通知模块 微信小程序 typeof(AbpNotificationsWeChatMiniProgramModule), // 多租户模块 版本 diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs index 96c338307..d6c9002df 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications.Templating; using LY.MicroService.RealtimeMessage.BackgroundJobs; using LY.MicroService.RealtimeMessage.MultiTenancy; using Microsoft.Extensions.Localization; @@ -74,6 +75,10 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed /// protected INotificationDataSerializer NotificationDataSerializer { get; } /// + /// Reference to . + /// + protected INotificationTemplateResolver NotificationTemplateResolver { get; } + /// /// Reference to . /// protected INotificationDefinitionManager NotificationDefinitionManager { get; } @@ -99,6 +104,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed IOptions options, INotificationStore notificationStore, INotificationDataSerializer notificationDataSerializer, + INotificationTemplateResolver notificationTemplateResolver, INotificationDefinitionManager notificationDefinitionManager, INotificationSubscriptionManager notificationSubscriptionManager, INotificationPublishProviderManager notificationPublishProviderManager) @@ -112,6 +118,7 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed StringLocalizerFactory = stringLocalizerFactory; NotificationStore = notificationStore; NotificationDataSerializer = notificationDataSerializer; + NotificationTemplateResolver = notificationTemplateResolver; NotificationDefinitionManager = notificationDefinitionManager; NotificationSubscriptionManager = notificationSubscriptionManager; NotificationPublishProviderManager = notificationPublishProviderManager; @@ -135,23 +142,25 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed } using (CultureHelper.Use(culture, culture)) { + var result = await NotificationTemplateResolver.ResolveAsync(eventData.Data); + if (notification.NotificationType == NotificationType.System) { using (CurrentTenant.Change(null)) { - await SendToTenantAsync(null, notification, eventData); + await SendToTenantAsync(null, notification, eventData, result); var allActiveTenants = await TenantConfigurationCache.GetTenantsAsync(); foreach (var activeTenant in allActiveTenants) { - await SendToTenantAsync(activeTenant.Id, notification, eventData); + await SendToTenantAsync(activeTenant.Id, notification, eventData, result); } } } else { - await SendToTenantAsync(eventData.TenantId, notification, eventData); + await SendToTenantAsync(eventData.TenantId, notification, eventData, result); } } } @@ -188,7 +197,8 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed protected async virtual Task SendToTenantAsync( Guid? tenantId, NotificationDefinition notification, - NotificationEto eventData) + NotificationEto eventData, + NotificationTemplateResolveResult templateResolveResult) { using (CurrentTenant.Change(tenantId)) { @@ -224,7 +234,8 @@ namespace LY.MicroService.RealtimeMessage.EventBus.Distributed // 由于模板通知受租户影响, 格式化失败的消息将被丢弃. message = await TemplateRenderer.RenderAsync( templateName: eventData.Data.Name, - model: eventData.Data.ExtraProperties, + // 解决序列化后的数据无法渲染模板 + model: templateResolveResult.Model ?? eventData.Data.ExtraProperties, cultureName: eventData.Data.Culture, globalContext: new Dictionary { diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj index b1adfb3ad..c8be1f727 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/LY.MicroService.RealtimeMessage.HttpApi.Host.csproj @@ -89,6 +89,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs index 2f970c91e..2029bf94a 100644 --- a/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.RealtimeMessage.HttpApi.Host/RealtimeMessageHttpApiHostModule.cs @@ -28,6 +28,7 @@ using LINGYUN.Abp.Notifications.EntityFrameworkCore; using LINGYUN.Abp.Notifications.Jobs; using LINGYUN.Abp.Notifications.SignalR; using LINGYUN.Abp.Notifications.Sms; +using LINGYUN.Abp.Notifications.Templating; using LINGYUN.Abp.Notifications.WeChat.MiniProgram; using LINGYUN.Abp.Notifications.WeChat.Work; using LINGYUN.Abp.Notifications.WxPusher; @@ -101,6 +102,7 @@ namespace LY.MicroService.RealtimeMessage; typeof(AbpNotificationsWeChatMiniProgramModule), typeof(AbpNotificationsWeChatWorkModule), typeof(AbpNotificationsExceptionHandlingModule), + typeof(AbpNotificationsTemplatingModule), typeof(AbpWeChatWorkHandlersModule), typeof(AbpWeChatOfficialHandlersModule), typeof(AbpIdentityNotificationsModule), diff --git a/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj b/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj index cceabf72e..17ebde66d 100644 --- a/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj +++ b/aspnet-core/templates/micro/PackageName.CompanyName.ProjectName.csproj @@ -3,13 +3,13 @@ net8.0 true LINGYUN.Abp.MicroService.Templates - 8.3.0 + 8.3.4 colin.in@foxmail.com Abp framework micro-service template MIT false https://github.com/colinin/abp-next-admin - micro webapi cloud + abp micro webapi cloud Template git https://github.com/colinin/abp-next-admin diff --git a/aspnet-core/templates/micro/content/Directory.Packages.props b/aspnet-core/templates/micro/content/Directory.Packages.props index af9607d7a..18e6f3e9a 100644 --- a/aspnet-core/templates/micro/content/Directory.Packages.props +++ b/aspnet-core/templates/micro/content/Directory.Packages.props @@ -2,8 +2,8 @@ 8.2.0 2.14.1 - 8.3.0 - 8.3.0 + 8.3.4 + 8.3.4 8.0.0 8.0.0 8.0.0 diff --git a/aspnet-core/templates/micro/content/common.props b/aspnet-core/templates/micro/content/common.props index d7d7622cf..6052366a9 100644 --- a/aspnet-core/templates/micro/content/common.props +++ b/aspnet-core/templates/micro/content/common.props @@ -1,12 +1,12 @@ latest - 8.2.1 + 8.3.4 colin $(NoWarn);CS1591;CS0436;CS8618;NU1803 https://github.com/colinin/abp-next-admin $(SolutionDir)LocalNuget - 8.2.1 + 8.3.4 MIT git https://github.com/colinin/abp-next-admin diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj index 6ee2a7fc9..32ccca462 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj @@ -31,10 +31,6 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -59,7 +55,7 @@ - + diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs index 092cdeb82..ad8792c62 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs @@ -23,15 +23,19 @@ public class Program Log.Information("Starting web host."); var builder = WebApplication.CreateBuilder(args); - builder.Host.AddAppSettingsSecretsJson() + builder.Host + .AddAppSettingsSecretsJson() .UseAutofac() .ConfigureAppConfiguration((context, config) => { - var configuration = config.Build(); - var agileConfigEnabled = configuration["AgileConfig:IsEnabled"]; - if (agileConfigEnabled.IsNullOrEmpty() || bool.Parse(agileConfigEnabled)) + var agileConfig = context.Configuration.GetSection("AgileConfig");//IsEnabled + if (agileConfig.Exists()) { - config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); + var isAgileConfigEnabled = agileConfig["IsEnabled"]; + if (isAgileConfigEnabled.IsNullOrWhiteSpace() || bool.Parse(isAgileConfigEnabled)) + { + config.AddAgileConfig(new AgileConfig.Client.ConfigClient(context.Configuration)); + } } }) .UseSerilog((context, provider, config) => @@ -45,12 +49,11 @@ public class Program options.ApplicationName = ProjectNameHttpApiHostModule.ApplicationName; // 搜索 Modules 目录下所有文件作为插件 // 取消显示引用所有其他项目的模块,改为通过插件的形式引用 - var pluginFolder = Path.Combine( - Directory.GetCurrentDirectory(), "Modules"); + var pluginFolder = Path.Combine(Directory.GetCurrentDirectory(), "Modules"); + DirectoryHelper.CreateIfNotExists(pluginFolder); - options.PlugInSources.AddFolder( - pluginFolder, - SearchOption.AllDirectories); + + options.PlugInSources.AddFolder(pluginFolder, SearchOption.AllDirectories); }); var app = builder.Build(); await app.InitializeApplicationAsync(); diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs index ea6e034c3..b943b09a6 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs @@ -1,12 +1,14 @@ +using LINGYUN.Abp.AspNetCore.HttpOverrides; using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; using LINGYUN.Abp.AuditLogging.Elasticsearch; using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.Identity.Session.AspNetCore; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; -using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; @@ -22,13 +24,11 @@ using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.DistributedLocking; using Volo.Abp.FeatureManagement.EntityFrameworkCore; using Volo.Abp.Http.Client.IdentityModel.Web; +using Volo.Abp.MailKit; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.Swashbuckle; -using LINGYUN.Abp.AspNetCore.HttpOverrides; -using LINGYUN.Abp.Identity.Session.AspNetCore; -using Volo.Abp.MailKit; namespace PackageName.CompanyName.ProjectName; diff --git a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json index b9c69ab64..4f3ee4d30 100644 --- a/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json +++ b/aspnet-core/templates/micro/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json @@ -1,4 +1,9 @@ { + "App": { + "CorsOrigins": "http://127.0.0.1:30000", + "RefreshClaimsUrl": "http://127.0.0.1:30015/", + "HealthChecks": "/healthz" + }, "Clock": { "Kind": "Local" }, @@ -44,6 +49,9 @@ "path": "Logs/Debug-.log", "restrictedToMinimumLevel": "Debug", "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" } }, @@ -53,6 +61,9 @@ "path": "Logs/Info-.log", "restrictedToMinimumLevel": "Information", "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" } }, @@ -62,6 +73,9 @@ "path": "Logs/Warn-.log", "restrictedToMinimumLevel": "Warning", "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" } }, @@ -71,6 +85,9 @@ "path": "Logs/Error-.log", "restrictedToMinimumLevel": "Error", "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" } }, @@ -80,6 +97,9 @@ "path": "Logs/Fatal-.log", "restrictedToMinimumLevel": "Fatal", "rollingInterval": "Day", + "rollOnFileSizeLimit": true, + "retainedFileCountLimit": 50, + "fileSizeLimitBytes": 5242880, "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" } } diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN.Abp.Notifications.Templating.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN.Abp.Notifications.Templating.Tests.csproj new file mode 100644 index 000000000..e4783658c --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN.Abp.Notifications.Templating.Tests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + + false + Debug;Release; + AnyCPU + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestBase.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestBase.cs new file mode 100644 index 000000000..c9d76e56e --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestBase.cs @@ -0,0 +1,8 @@ +using LINGYUN.Abp.Tests; + +namespace LINGYUN.Abp.Notifications.Templating; + +public class AbpNotificationsTemplatingTestBase : AbpTestsBase +{ + +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestModule.cs new file mode 100644 index 000000000..4fb515f7d --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/AbpNotificationsTemplatingTestModule.cs @@ -0,0 +1,14 @@ +using LINGYUN.Abp.Tests; +using Volo.Abp.Json; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.Templating; + +[DependsOn( + typeof(AbpNotificationsTemplatingModule), + typeof(AbpJsonModule), + typeof(AbpTestsBaseModule))] +public class AbpNotificationsTemplatingTestModule : AbpModule +{ + +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NewtownsoftJsonTemplateResolveContributor.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NewtownsoftJsonTemplateResolveContributor.cs new file mode 100644 index 000000000..6b93271c4 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NewtownsoftJsonTemplateResolveContributor.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json.Linq; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Templating; +internal class NewtownsoftJsonTemplateResolveContributor : INotificationTemplateResolveContributor +{ + public string Name => "ToDynamic"; + + public Task ResolveAsync(INotificationTemplateResolveContext context) + { + var jsonObject = new JObject(); + foreach (var prop in context.Template.ExtraProperties) + { + jsonObject.Add(prop.Key, prop.Value.ToString()); + } + context.Model = jsonObject.ToObject(); + + return Task.CompletedTask; + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationModel.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationModel.cs new file mode 100644 index 000000000..4122ff61b --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationModel.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.Notifications.Templating; + +public class NotificationSimpleModel +{ + public string Name { get; set; } + public string Firend { get; set; } +} + +public class NotificationModel +{ + public string Name { get; set; } + public List Jobs { get; set; } +} + +public class NotificationJob +{ + public string Name { get; set; } + public NotificationJob() + { + + } + + public NotificationJob(string name) + { + Name = name; + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolverTests.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolverTests.cs new file mode 100644 index 000000000..70b14f5ea --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/NotificationTemplateResolverTests.cs @@ -0,0 +1,75 @@ +using LINGYUN.Abp.RealTime; +using Newtonsoft.Json; +using Shouldly; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Json; +using Xunit; + +namespace LINGYUN.Abp.Notifications.Templating; +public class NotificationTemplateResolverTests : AbpNotificationsTemplatingTestBase +{ + private IJsonSerializer _jsonSerializer; + public NotificationTemplateResolverTests() + { + _jsonSerializer = GetRequiredService(); + } + + [Fact] + public async Task Resolve_Deserialize_To_Object() + { + var notificationTemplate = new NotificationTemplate( + "Test", + data: new Dictionary + { + { "Name", "Tom" }, + { "Jobs", new List + { + new NotificationJob("Catch Jerry"), + new NotificationJob("Hit Pike") + } + } + }); + + var receivedEto = _jsonSerializer.Deserialize>( + _jsonSerializer.Serialize( + new RealTimeEto(notificationTemplate))); + + var contributor = new ToObjectNotificationTemplateResolveContributor(); + var context = new NotificationTemplateResolveContext(receivedEto.Data, ServiceProvider); + + await contributor.ResolveAsync(context); + + var model = context.Model.ShouldBeOfType(); + model.Name.ShouldBe("Tom"); + model.Jobs.Count.ShouldBe(2); + model.Jobs[0].Name.ShouldBe("Catch Jerry"); + model.Jobs[1].Name.ShouldBe("Hit Pike"); + } + + [Fact] + public async Task Resolve_Deserialize_To_Dynamic() + { + var notificationTemplate = new NotificationTemplate( + "Test", + data: new Dictionary + { + { "Name", "Tom" }, + { "Firend", "Jerry" } + }); + + var receivedEto = _jsonSerializer.Deserialize>( + _jsonSerializer.Serialize( + new RealTimeEto(notificationTemplate))); + + var contributor = new NewtownsoftJsonTemplateResolveContributor(); + var context = new NotificationTemplateResolveContext(receivedEto.Data, ServiceProvider); + + await contributor.ResolveAsync(context); + + dynamic model = context.Model; + + Assert.Equal(model.Name, "Tom"); + Assert.Equal(model.Firend, "Jerry"); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/ToObjectNotificationTemplateResolveContributor.cs b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/ToObjectNotificationTemplateResolveContributor.cs new file mode 100644 index 000000000..b3a410f84 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Notifications.Templating.Tests/LINGYUN/Abp/Notifications/Templating/ToObjectNotificationTemplateResolveContributor.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.Json; + +namespace LINGYUN.Abp.Notifications.Templating; +internal class ToObjectNotificationTemplateResolveContributor : INotificationTemplateResolveContributor +{ + public string Name => "ToObject"; + + public Task ResolveAsync(INotificationTemplateResolveContext context) + { + var model = new NotificationModel(); + + var nameObj = context.Template.GetProperty(nameof(NotificationModel.Name)); + model.Name = nameObj.ToString(); + + var jobsObj = context.Template.GetProperty(nameof(NotificationModel.Jobs)); + + var jsonSerializer = context.ServiceProvider.GetRequiredService(); + + model.Jobs = jsonSerializer.Deserialize>(jobsObj.ToString()); + + context.Model = model; + + return Task.CompletedTask; + } +}