ABP文档 - 通知系统
本节内容:
简介
通知用来告知用户系统里特定的事件发生了,ABP提供一个发布/订阅,它基于实时通知基础框架。
发送模式
有两种方式可以发送通知给用户:
- 用户订阅一个特定的通知类型,然后我们发布一个此类型的通知,它会分发给所有订阅的用户,这就是发布/订阅模式。
- 我们可以直接发送一个通知给目标用户(users)。
通知类型
有两种通知类型:
- 一般通知:任意的通知类型,“如果一个用户发送一个好友请求,那么通知我”就是一个此类型的通知。
- 实体通知:与一个特定的实体关联,“如果一个用户给这张(photo)图片发了评论,那么通知我”就是一个基于实体的通知,因为它与一个特定的photo实体关联,用户可能想为某些图片发出通知,而不是所有图片。
通知数据
一个通知通常包含一个通知数据,例如:“如果一个用户发送一个好友请求,那么通知我”该通知可能有两个数据属性:发送者名字(谁发送了这个好友请求)和备注(发送者写在请求里的信息),很明显,通知数据类型与通知类型是紧密联系的,不同的通知类型有不同的数据类型。
通知数据是可选的,有些通知可能就不需要数据。ABP已经提供足以满足大部分情况的预定义通知数据类型,简单的信息可以用MessageNotificationData,本地化和可参数化的通知信息可以使用LocalizableMessageNotificationData,我们会在以后章节看到使用示例。
通知重要性
通知重要性有5个级别,定义在NotificationSeverity枚举里:Info,Success,Warn,Error和Fatal,默认为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": ,
- "state": ,
- "notification": {
- "notificationName": "System.LowDisk",
- "data": {
- "message": {
- "sourceName": "MyLocalizationSourceName",
- "name": "LowDiskWarningMessage"
- },
- "type": "Abp.Notifications.LocalizableMessageNotificationData",
- "properties": {
- "remainingDiskInMb": ""
- }
- },
- "entityType": null,
- "entityTypeName": null,
- "entityId": null,
- "severity": ,
- "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<MyAppNotificationProvider>();
- }
- //...
- }
最后,你可以在你应用中注入并使用INotificationDefinitionManager来获取通知定义,接着你可能想准备一个允许用户自己订阅这些通知的页面。
kid1412附:英文原文:http://www.aspnetboilerplate.com/Pages/Documents/Notification-System
ABP文档 - 通知系统的更多相关文章
- ABP文档笔记系列
ABP文档笔记 - 模块系统 及 配置中心 ABP文档笔记 - 事件BUS ABP文档笔记 - 数据过滤 ABP文档笔记 - 规约 ABP文档笔记 - 配置.设置.版本.功能.权限 ABP文档笔记 - ...
- 基于Noootes/Dooomino的文档工作流系统(转)
(流程样例应用程序终于整理上传好可供下载了http://download.csdn.net/download/starrow/8422299) 上文分析了我们的流程配置使用三类对象,分别对应三类文档: ...
- mindoc 在线文档接口系统的 docker 制作过程
说明: mindoc 是一款在线接口文档编辑系统,百度一下就知道了.github地址:https://github.com/lifei6671/mindoc 本机:ubuntu16.04 + dock ...
- groff - groff 文档排版系统前端
总览 (SYNOPSIS) groff [ -abehilpstvzCENRSUVXZ ] [ -wname ] [ -Wname ] [ -mname ] [ -Fdir ] [ -Idir ] [ ...
- troff - groff 文档排版系统的 troff 处理器
总览 SYNOPSIS troff [ -abcivzCERU ] [ -d cs ] [ -f fam ] [ -F dir ] [ -m name ] [ -M dir ] [ -n num ] ...
- ABP文档笔记 - 通知
基础概念 两种通知发送方式 直接发送给目标用户 用户订阅某类通知,发送这类通知时直接分发给它们. 两种通知类型 一般通知:任意的通知类型 "如果一个用户发送一个好友请求,那么通知我" ...
- ABP文档 - SignalR 集成
文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用 ...
- ABP理论学习之通知系统
返回总目录 本篇目录 介绍 订阅通知 发布通知 用户通知管理者 实时通知 通知存储 通知定义 介绍 通知(Notification)用于告知用户系统中的特定事件.ABP提供了基于实时通知基础设施的发布 ...
- ABP文档 - Javascript Api - AJAX
本节内容: AJAX操作相关问题 ABP的方式 AJAX 返回信息 处理错误 HTTP 状态码 WrapResult和DontWrapResult特性 Asp.net Mvc 控制器 Asp.net ...
随机推荐
- NodeJs之OS
OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...
- ASP.NET Core 中的那些认证中间件及一些重要知识点
前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...
- 在.NET Core 里使用 BouncyCastle 的DES加密算法
.NET Core上面的DES等加密算法要等到1.2 才支持,我们可是急需这个算法的支持,文章<使用 JavaScriptService 在.NET Core 里实现DES加密算法>需要用 ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- AngularJs之九(ending......)
今天继续angularJs,但也是最后一篇关于它的了,基础部分差不多也就这些,后续有机会再写它的提升部分. 今天要写的也是一个基础的选择列表: 一:使用ng-options,数组进行循环. <d ...
- HDU1671——前缀树的一点感触
题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...
- iOS逆向工程之KeyChain与Snoop-it
今天博客的主题是Keychain, 在本篇博客中会通过一个登陆的Demo将用户名密码存入到KeyChain中,并且查看一下KeyChain中存的是什么东西,把这些内容给导出来.当然本篇博客的重点不是如 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
- 读书笔记汇总 - SQL必知必会(第4版)
本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...