From e68dea143e1cb93c7c46111fcbe3b06f76b1dfab Mon Sep 17 00:00:00 2001 From: colin Date: Mon, 18 May 2026 13:57:16 +0800 Subject: [PATCH] feat: Add notification publish interceptor --- .../INotificationPublishInterceptor.cs | 20 +++++ .../NotificationPublishProvider.cs | 77 ++++++++++++++++++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs new file mode 100644 index 000000000..27437a1b5 --- /dev/null +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublishInterceptor.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications; +/// +/// 通知发布拦截器, 实现此接口来增加发布前的自定义检查 +/// +public interface INotificationPublishInterceptor +{ + /// + /// 拦截优先级,数值越小优先级越高 + /// + int Priority { get; } + + /// + /// 在通知发布前执行检查 + /// + /// 通知信息 + /// true-允许发布, false-阻止发布 + Task CanPublishAsync(NotificationInfo notification); +} diff --git a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs index 8bf1cc899..8e52907a7 100644 --- a/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs +++ b/aspnet-core/modules/realtime-notifications/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationPublishProvider.cs @@ -1,6 +1,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -21,6 +23,11 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider public ICancellationTokenProvider CancellationTokenProvider => ServiceProvider.LazyGetService(NullCancellationTokenProvider.Instance); + private IEnumerable _interceptors; + protected IEnumerable Interceptors => + _interceptors ??= ServiceProvider.LazyGetService>() + ?? Enumerable.Empty(); + public async virtual Task CanPublishAsync(NotificationInfo notification) { return await CanPublishAsync(notification, GetCancellationToken()); @@ -28,9 +35,23 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider public async Task PublishAsync(NotificationPublishContext context) { - await PublishAsync(context, GetCancellationToken()); + var cancellationToken = GetCancellationToken(); + + // 通知拦截器检查 + if (!await ExecuteInterceptorsAsync(context, cancellationToken)) + { + return; + } + + await PublishAsync(context, cancellationToken); } + /// + /// 是否允许发布通知 + /// + /// + /// + /// protected virtual Task CanPublishAsync( NotificationInfo notification, CancellationToken cancellationToken = default) @@ -38,6 +59,60 @@ public abstract class NotificationPublishProvider : INotificationPublishProvider return Task.FromResult(true); } + /// + /// 执行通知发布拦截器 + /// + /// + /// + /// + protected virtual async Task ExecuteInterceptorsAsync( + NotificationPublishContext context, + CancellationToken cancellationToken = default) + { + if (context.Notification.Type == NotificationType.System || + context.Notification.Type == NotificationType.ServiceCallback) + { + Logger.LogDebug( + "System or service callback notification {NotificationName}, skip all interceptors.", + context.Notification.Name); + return true; + } + + if (!Interceptors.Any()) + { + Logger.LogDebug("No notification publishing interceptors have been registered."); + return true; + } + + var orderedInterceptors = Interceptors.OrderBy(i => i.Priority); + + foreach (var interceptor in orderedInterceptors) + { + try + { + if (!await interceptor.CanPublishAsync(context.Notification)) + { + var reason = string.Format("The interceptor {0} prevented the publication of the notification {1}.", + interceptor.GetType().Name, + context.Notification.Name); + + context.Cancel(reason); + + Logger.LogWarning(reason); + return false; + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, + "An exception occurred while executing the interceptor {InterceptorType}. By default, publication is allowed.", + interceptor.GetType().Name); + } + } + + return true; + } + protected virtual CancellationToken GetCancellationToken(CancellationToken cancellationToken = default) { return CancellationTokenProvider.FallbackToProvider(cancellationToken);