热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ABP文档通知系统

文档目录本节内容:简介发送模式通知类型通知数据通知重要性关于通知持久化订阅通知发布通知用户通知管理器实时通知客户端通知存储通知定义简介通知用来告知用户系统里特定的事件

文档目录

 

本节内容:

  • 简介
    • 发送模式
    • 通知类型
    • 通知数据
    • 通知重要性
    • 关于通知持久化
  • 订阅通知
  • 发布通知
  • 用户通知管理器
  • 实时通知
    • 客户端
  • 通知存储
  • 通知定义

 

简介

通知用来告知用户系统里特定的事件发生了,ABP提供一个发布/订阅,它基于实时通知基础框架。

 

发送模式

有两种方式可以发送通知给用户:

  • 用户订阅一个特定的通知类型,然后我们发布一个此类型的通知,它会分发给所有订阅的用户,这就是发布/订阅模式。
  • 我们可以直接发送一个通知给目标用户(users)。

 

通知类型

有两种通知类型:

  • 一般通知:任意的通知类型,“如果一个用户发送一个好友请求,那么通知我”就是一个此类型的通知。
  • 实体通知:与一个特定的实体关联,“如果一个用户给这张(photo)图片发了评论,那么通知我”就是一个基于实体的通知,因为它与一个特定的photo实体关联,用户可能想为某些图片发出通知,而不是所有图片。

通知数据

一个通知通常包含一个通知数据,例如:“如果一个用户发送一个好友请求,那么通知我”该通知可能有两个数据属性:发送者名字(谁发送了这个好友请求)和备注(发送者写在请求里的信息),很明显,通知数据类型与通知类型是紧密联系的,不同的通知类型有不同的数据类型。

通知数据是可选的,有些通知可能就不需要数据。ABP已经提供足以满足大部分情况的预定义通知数据类型,简单的信息可以用MessageNotificationData,本地化和可参数化的通知信息可以使用LocalizableMessageNotificationData,我们会在以后章节看到使用示例。

 

通知重要性

通知重要性有5个级别,定义在NotificationSeverity枚举里:Info,Success,Warn,ErrorFatal,默认为Info

关于通知持久化

查看通知存储小节获取更多信息。

 

订阅通知

INotificationSubscriptionManager提供了用来订阅通知的API,例如:

public class MyService : ITransientDependency
{
private readonly INotificationSubscriptionManager _notificationSubscriptionManager;public MyService(INotificationSubscriptionManager notificationSubscriptionManager){_notificationSubscriptionManager = notificationSubscriptionManager;}//订阅一个一般通知public async Task Subscribe_SentFrendshipRequest(int? tenantId, long userId){await _notificationSubscriptionManager.SubscribeAsync(new UserIdentifier(tenantId, userId), "SentFrendshipRequest"); }//订阅一个实体通知public async Task Subscribe_CommentPhoto(int? tenantId, long userId, Guid photoId){await _notificationSubscriptionManager.SubscribeAsync(new UserIdentifier(tenantId, userId), "CommentPhoto", new EntityIdentifier(typeof(Photo), photoId)); }
}
 

首先,我们注入INotificationSubscriptionManager,第一方法订阅一个一般通知,当某人发送一个好友请求时,用户会收到通知,第二个订阅一个与特定实体(Photo)相关的通知,当某人给特定照片写评论后,用户会收到通知。

每一个通知类型都应当有一个唯一的名称(如示例中的SentFrendshipRequest 和CommentPhoto)。

INotificationSubscriptionManager还有UnsubscribeAsync,IsSubscribedAsync,GetSubscriptionsAsyn等方法来管理订阅。

 

发布通知

INotificationPublisher用来发布通知,例如:

public class MyService : ITransientDependency
{
private readonly INotificationPublisher _notiticationPublisher;public MyService(INotificationPublisher notiticationPublisher){_notiticationPublisher = notiticationPublisher;}//发送一个一般通知给一个特定用户public async Task Publish_SentFrendshipRequest(string senderUserName, string friendshipMessage, UserIdentifier targetUserId){await _notiticationPublisher.PublishAsync("SentFrendshipRequest", new SentFrendshipRequestNotificationData(senderUserName, friendshipMessage), userIds: new[] { targetUserId });}//发送一个实体通知给一个特定用户public async Task Publish_CommentPhoto(string commenterUserName, string comment, Guid photoId, UserIdentifier photoOwnerUserId){await _notiticationPublisher.PublishAsync("CommentPhoto", new CommentPhotoNotificationData(commenterUserName, comment), new EntityIdentifier(typeof(Photo), photoId), userIds: new[] { photoOwnerUserId });}//发送一个一般通知给所有当前租户(在会话里)里的订阅它的用户public async Task Publish_LowDisk(int remainingDiskInMb){//Example "LowDiskWarningMessage" content for English -> "Attention! Only {remainingDiskInMb} MBs left on the disk!" var data = new LocalizableMessageNotificationData(new LocalizableString("LowDiskWarningMessage", "MyLocalizationSourceName"));data["remainingDiskInMb"] = remainingDiskInMb;await _notiticationPublisher.PublishAsync("System.LowDisk", data, severity: NotificationSeverity.Warn); }
}
 

在第一个例子里, 我们发布一个通知给一个单独的用户,SentFrendshipRequestNotificationData应该继承于NotificationData,如下所示:

[Serializable]
public class SentFrendshipRequestNotificationData : NotificationData
{
public string SenderUserName { get; set; }public string FriendshipMessage { get; set; }public SentFrendshipRequestNotificationData(string senderUserName, string friendshipMessage){SenderUserName = senderUserName;FriendshipMessage = friendshipMessage;}
}
 

第二个例子,我们发送一个通知给一个特定用户并传递一个特定实体,通知数据类不需要可序列化(因为默认使用JSON序列器),但建议把它标记为可序列化,因为你可能会在不同应用中移动而且你将来也可能想使用二进制可序列化器。当然如前面所述,通知数据是可选的,并不是所有的通知都需要它。

注意:如果我们发布一个通知给一个特定用户,那么这个用户不需要订阅这个通知。

第三个例子,我们没有定义一个专用的通知数据类,而是直接使用内容的LocalizableMessageNotificationData类,并使用基于字典的数据,并发布一个“Warn”通知,LocalizableMessageNotificationData可以存储基于字典的任意数据(如果自定义的通知数据类继承于NotificationData类,那么也可以这么用),我们使用“remainingDiskInMb”作为本地化参数,本地化信息可以包含这些参数(如示例中的“Attention!Only{remainingDiskInMb} MBs left on the disk!”),我们在客户端小节里可以看到如果本地化。

 

用户通知管理器

IUserNotificationManager用来管理用户的通知,它get,update或delete一个用户的通知,你可以用它为你的应用准备一个通知列表页面。

 

实时通知

虽然你可以用IUserNotificationManager来查询通知,但我们通常想推送一个实时通知到客户端。

通知系统使用IRealTimeNotifier来发送实时通知给用户,这可以使用任何类型的实时通讯系统实现,我们可以用一个单独实现的SignalR包,启动模板已经安装了SignalR,查看SignalR集成文档获取更多信息。

注意:通知系统用一个后台作业异步调用IRealTimeNotifier,所以,通知可能会有一点点的延迟。

 

客户端

当接收到一个实时的通知,ABP在客户端触发一个全局事件,你可以用如下的方式注册来得到通知:

abp.event.on('abp.notifications.received', function (userNotification) {console.log(userNotification);
});
 

每接收到一个实时通知,都会触发abp.notifications.received事件事件,你可以像上面那样注册该事件来获取通知,查看Javascript事件总线文档获取事件更多信息。一个收到的“System.LowDisk”通知的Json示例:

{"userId": 2,"state": 0,"notification": {"notificationName": "System.LowDisk","data": {"message": {"sourceName": "MyLocalizationSourceName","name": "LowDiskWarningMessage"},"type": "Abp.Notifications.LocalizableMessageNotificationData","properties": {"remainingDiskInMb": "42"}},"entityType": null,"entityTypeName": null,"entityId": null,"severity": 0,"creationTime": "2016-02-09T17:03:32.13","id": "0263d581-3d8a-476b-8e16-4f6a6f10a632"},"id": "4a546baf-bf17-4924-b993-32e420a8d468"
}

在这个对象里:

  • userId:当前用户Id,通常你不需要这个因为你知道当前的户。
  • state:UserNotificationState的枚举值,0:Unread(未读),1:Read(已读)。
  • notification:通知明细:
    • notificationName:这个通知的唯一名称(发布时也用这个名称)。
    • data:通知数据,在这个示例里,我们使用LocalizableMessageNotificationData(和之前发布的示例一致):
      • message:本地化的消息信息,我们可以用sourceName和name来本地化界面上的消息。
      • type:通知数据类型,全类型名,包含命名空间,当在处理通知数据时,我们可以检查这个类型。
      • properties:基于字典的自定义属性。
    • entityType、entityTypeName和entityId:实体信息(如果这是一个实体实时通知)
    • severity:一个NotificationSeverity枚举值,0:Info,1:Success,2:Warn,3:Error,4:Fatal。
    • id:通知Id。
  • id:用户通知Id。

当然,你不会只是日志这个通知,你可以使用通知数据把通知信息显示给用户,例如:

abp.event.on('abp.notifications.received', function (userNotification) {if (userNotification.notification.data.type === 'Abp.Notifications.LocalizableMessageNotificationData') {var localizedText = abp.localization.localize(userNotification.notification.data.message.name,userNotification.notification.data.message.sourceName);$.each(userNotification.notification.data.properties, function (key, value) {localizedText = localizedText.replace('{' + key + '}', value);});alert('New localized notification: ' + localizedText);} else if (userNotification.notification.data.type === 'Abp.Notifications.MessageNotificationData') {alert('New simple notification: ' + userNotification.notification.data.message);}
});

为了能处理通知数据,我们应当检查这个数据类型,这个例子简单的从通知数据里获取消息,如果是本地化的消息(LocalizableMessageNotificationData),我们本地化这个消息并替换参数, 如果是简单消息(MessageNotificationData),我们直接获取这个消息,当然,在真实的项目里,我们不会使用alert函数,我们可以使用abp.notify api来显示良好的UI通知。

如果你想实现上面这样的逻辑,有一个更容易且富有弹性的方式,当接收到一个推送的通知,你只需要一行代码来显示UI通知:

abp.event.on('abp.notifications.received', function (userNotification) {abp.notifications.showUiNotifyForUserNotification(userNotification);
});

这显示一个UI通知,如下所示(上面描述的推送的System.LowDisk通知):

它可工作于内容的通知数据类型(LocalizableMessageNotificationData和MessageNotificationData),如果你是自定义的通知数据类型,那么你应该像下面这样注册数据格式:

abp.notifications.messageFormatters['MyProject.MyNotificationDataType'] = function(userNotification) {return ...; //此处格式化并返回消息
};

 

因此,showUiNotifyForUserNotification可以为你的数据类型创建显示的消息,如果你只是需要格式的消息,你可以直接使用abp.notifications.getFormattedMessageFromUserNotification

(userNotification), 它内部被showUiNotifyForUserNotification。

启动模板包含了当接收到一个推送信息后显示UI通知的代码。

 

通知存储

通知系统使用INotificationStore来持久化通知,该接口实现后才能使通知系统正常工作,你可以自己实现它或使用已经实现它的module-zero。

 

通知定义

你不需要在用前先定义一个通知,你只管使用任何通知名称而无需定义,但是,定义它可能给你带来额外的好处,例如,定义后你可以在你的应用里检查所有的通知。鉴于这种情况,我们可以为我们的模块定义一个通知供应器,如下所示:

public class MyAppNotificationProvider : NotificationProvider
{
public override void SetNotifications(INotificationDefinitionContext context){context.Manager.Add(new NotificationDefinition("App.NewUserRegistered",displayName: new LocalizableString("NewUserRegisteredNotificationDefinition", "MyLocalizationSourceName"),permissionDependency: new SimplePermissionDependency("App.Pages.UserManagement")));}
}

 

“Abp.NewUserRegistered”是这个通知的唯一名称,我们定义了一个可本地化的displayName(当在UI上订阅这个通知时可以显示它),最后,我们声明这个通知只对拥有“App.Pages.UserManagerment”许可的用户可用。

这里还有一些其它参数,你可以在代码中检查它,一个通知的定义只有名称是必需的。

在定义好这个通知供应器后,我们应该在模块的PreInitialize事件里注册它,如下所示:

public class AbpZeroTemplateCoreModule : AbpModule
{
public override void PreInitialize(){Configuration.Notifications.Providers.Add();}//...
}

 

最后,你可以在你应用中注入并使用INotificationDefinitionManager来获取通知定义,接着你可能想准备一个允许用户自己订阅这些通知的页面。

 

kid1412附:英文原文:http://www.aspnetboilerplate.com/Pages/Documents/Notification-System



推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • mysql-cluster集群sql节点高可用keepalived的故障处理过程
    本文描述了mysql-cluster集群sql节点高可用keepalived的故障处理过程,包括故障发生时间、故障描述、故障分析等内容。根据keepalived的日志分析,发现bogus VRRP packet received on eth0 !!!等错误信息,进而导致vip地址失效,使得mysql-cluster的api无法访问。针对这个问题,本文提供了相应的解决方案。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
author-avatar
他给我留下的美好_813
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有