Introduction

Notifications are used to inform users on specific events in the system. ASP.NET Boilerplate provides a pub/sub based real time notification infrastructure.

通知用于通知用户系统中的特定事件。ASP.NET的模板提供了一个基于实时通知基建Pub/Sub。

Sending Models(发送模式)

There are two ways of sending notifications to users:

  • User subscribes to a specific notification type. Then we publish a notification of this type which is delivered to all subscribed users. This is the pub/sub model.
  • 用户订阅特定的通知类型。然后,我们发布这种类型的通知,该通知传递给所有订阅用户。这是pub/sub模型。
  • We can directly send a notification to target user(s).

Notification Types(通知类型)

There are also two types of notifications:

  • General notifications are arbitrary type of notifications. "Notify me if a user sends me a friendship request" is an example of this type notifications.
  • 一般通知是任意类型的通知。如果用户发送了一个友好请求,请通知我“这是此类通知的一个示例。
  • Entity notifications are associated to a specific entity. "Notify me if a user comment on this photo" is an entity based notification since it's associated to a specific photo entity. Users may want to get notifications for some photos, not for all.
  • 实体通知与特定实体相关联。”如果用户评论这张照片,请通知我“它是一个基于实体的通知,因为它与特定的照片实体相关联。用户可能希望获得一些照片的通知,而不是所有的照片。

Notification Data

A notification generally include a notification data. For example: "Notify me if a user sends me a friendship request" notification may have two data properties: sender user name (which user sent this friendship request) and request note (a note that user did write in the request). It's obvious that the notification data type is tightly coupled to notification types. Different notification types have different data types.

Notification data is optional. Some notifications may not require a data. There are some pre-defined notification data types those can be enough for most cases. MessageNotificationData can be used for simple messages and LocalizableMessageNotificationData can be used for localizable and parametric notification messages. We will see example usage in later sections.

通知数据是可选的。有些通知可能不需要数据。有一些预定义的通知数据类型,大多数情况下这些数据类型是足够的。messagenotificationdata可以用于简单的消息和localizablemessagenotificationdata可用于定位和参数的通知消息。我们将在后面的部分中看到示例用法。

Notification Severity(通知的严重程度)

There are 5 levels of notification severity, defined in NotificationSeverity enum: Info, Success, Warn, Error and Fatal. Default value is Info.

About Notification Persistence(关于通知的持久性)

See Notification Store section for more information on notification persistence.

Subscribe to Notifications(订阅通知)

INotificationSubscriptionManager provides API to subscribe to notifications. Examples:

public class MyService : ITransientDependency
{
private readonly INotificationSubscriptionManager _notificationSubscriptionManager; public MyService(INotificationSubscriptionManager notificationSubscriptionManager)
{
_notificationSubscriptionManager = notificationSubscriptionManager;
} //Subscribe to a general notification
public async Task Subscribe_SentFrendshipRequest(int? tenantId, long userId)
{
await _notificationSubscriptionManager.SubscribeAsync(new UserIdentifier(tenantId, userId), "SentFrendshipRequest");
} //Subscribe to an entity notification
public async Task Subscribe_CommentPhoto(int? tenantId, long userId, Guid photoId)
{
await _notificationSubscriptionManager.SubscribeAsync(new UserIdentifier(tenantId, userId), "CommentPhoto", new EntityIdentifier(typeof(Photo), photoId));
}
}

First, we injected INotificationSubscriptionManager. First method subscribes to a general notification. User wants to get notified when someone sends a friendship request. Second one subscribes to a notification related to a specific entity (Photo). User wants to get notified if anyone write comment to a specified photo.

首先,我们注入inotificationsubscriptionmanager。第一种方法订阅一般通知。当有人发送友情请求时,用户希望得到通知。二个订阅某一特定实体相关的通知(照片)。用户希望得到通知,如果有人对指定的照片发表评论。

Every notification type should have unique names (like SentFrendshipRequest and CommentPhoto in the samples)

每个通知类型必须具有唯一的名称(如样品中sentfrendshiprequest和commentphoto)

INotificationSubscriptionManager has also UnsubscribeAsync, IsSubscribedAsync, GetSubscriptionsAsync... methods to manage subscriptions.

Publish Notifications(发布通知)

INotificationPublisher is used to publish notifications. Examples:

public class MyService : ITransientDependency
{
private readonly INotificationPublisher _notiticationPublisher; public MyService(INotificationPublisher notiticationPublisher)
{
_notiticationPublisher = notiticationPublisher;
} //Send a general notification to a specific user
public async Task Publish_SentFrendshipRequest(string senderUserName, string friendshipMessage, UserIdentifier targetUserId)
{
await _notiticationPublisher.PublishAsync("SentFrendshipRequest", new SentFrendshipRequestNotificationData(senderUserName, friendshipMessage), userIds: new[] { targetUserId });
} //Send an entity notification to a specific user
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 });
} //Send a general notification to all subscribed users in current tenant (tenant in the session)
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);
}
}

In the first example, we published a notification to a single user. SentFrendshipRequestNotificationData should be derived from NotificationData like that:

[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;
}
}

In the second example, we sent a notification to a specific user for a specific entity. Notification data classes don't need to be serialzable normally (since JSON serialization is used by default). But it's suggested to mark it as serializable since you may need to move notifications between applications and may want to use binary serialization in the future. Also, as declared before, notification data is optional and may not be required for all notifications.

在第二个示例中,我们为特定实体发送通知给特定用户。通知数据的类不需要serialzable正常(由于JSON序列化是默认使用)。但它的建议将其标记为可序列化的因为你可能需要移动应用程序之间和通知可能要在未来使用二进制序列化。此外,正如前面声明的那样,通知数据是可选的,可能不需要所有通知。

Note: If we publish a notification to specific users, they don't need to be subscribed to those notifications.

注意:如果我们向特定用户发布通知,则不需要订阅这些通知。

In the third example, we did not define a dedicated notification data class. instead, directly used built-in LocalizableMessageNotificationData with dictionary based data and published notification as 'Warn'.LocalizableMessageNotificationData can store dictionary-based arbitrary data (this is also true for custom notification data classes since they also inherit from NotificationData class). We used "remainingDiskInMb" as argument on localization. Localization message can include these arguments (like "Attention! Only {remainingDiskInMb} MBs left on the disk!" in the example). We will see how to localize it in the Client Side section.

在第三个例子中,我们没有定义一个专用的通知数据类。相反,直接使用基于字典的数据和公布的通知,警告“内置localizablemessagenotificationdata。localizablemessagenotificationdata可以存储任意数据字典的基础(这也是真正的自定义通知数据类,因为他们也可以从notificationdata类)。我们用“remainingdiskinmb”作为参数对定位。本地化消息可以包含这些参数(如“注意”)!MBs left on the disk!”在例子中)。我们将看到如何在客户端部分本地化它。

User Notification Manager

IUserNotificationManager is used to manage notifications of users. It has methods to get, update or delete notifications for a user. You can use it to prepare a notification list page for your application.

Real Time Notifications

While you can use IUserNotificationManager to query notifications, we generally want to push real time notifications to the client.

Notification system uses IRealTimeNotifier to send real time notifications to users. This can be implemented with any type of real time communication system. It's implemented using SignalR in a seperated package. Startup templates have already SignalR installed. See SignalR Integration document for more information.

Note: Notification system calls IRealTimeNotifier asynchronously in a background job. So, notifications may be sent with a small delay.

Client Side

When a real time notification is received, ASP.NET Boilerplate triggers a global event in the client side. You can register like that to get notifications:

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

abp.notifications.received event is triggered for each received real time notification. You can register to this event as shown above to get notifications. See javascript event bus documentation for more information on events. An example incoming notification JSON for "System.LowDisk" example:

abp.notifications.received事件触发每个收到实时通知。您可以像上面显示的那样注册这个事件来获得通知。有关事件的更多信息,请参见JavaScript事件总线文档。例来信通知JSON”system.lowdisk”

{
"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"
}

In this object;

  • userId: Current user id. Generally you don't need this since you know the current user.
  • 当前用户ID。一般来说,您不需要这个,因为您知道当前用户。
  • state: Value of UserNotificationState enum. 0: Unread, 1: Read.
  • notification: Notification details.
    • notificationName: Unique name of the notification (same value used while publishing the notification).
    • data: notification data. In this example, we used LocalizableMessageNotificationData (as published in the example before).
      • message: Localizable message information. We can use sourceName and name to localize message on the UI.
      • type: Notification data type. Full type name, including namespaces. We can check this type while processing the notification data.
      • properties: Dictionary based custom properties.基于字典的自定义属性
    • entityType, entityTypeName and entityId: Entity information if this is an entity related notification.
    • severity: Value of NotificationSeverity enum. 0: Info, 1: Success, 2: Warn, 3: Error, 4: Fatal.
    • creationTime: Time of when this notification is created.
    • id: Notification id.
  • id: User notification id.

Surely, you will not just log the notification. You can use notification data to show notification information to the user. Example:

当然,您不只是记录通知。可以使用通知数据向用户显示通知信息。例子:

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);
}
});

To be able to process notification data, we should check the data type. This example simply gets message from notification data. For the localized message (LocalizableMessageNotificationData), we are localizing the message and replacing parameters. For simple message (MessageNotificationData), we directly get the message. Surely, in a real project, we will not use alert function. We can use abp.notify api to show nice UI notifications.

为了能够处理通知数据,我们应该检查数据类型。这个示例只从通知数据获取消息。的本地化消息(localizablemessagenotificationdata),我们是本地化的信息替换参数。对于简单的信息(messagenotificationdata),我们直接得到的消息。当然,在实际的项目中,我们不会使用警报功能。我们可以用abp.notify API显示漂亮的UI通知。

If you need to implement such a logic above, there is an easier and scaleable way. You can just use single line of code to show a UI notification when a push notification is received:

如果你想实现这样的逻辑之上,有一个更简单的和可扩展的方式。当接收到推送通知时,您可以只使用单行代码显示UI通知:

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

This shows a UI notification like that (for System.LowDisk notification published above):

It works for built-in notification data types (LocalizableMessageNotificationData and MessageNotificationData). If you have custom notification data types, then you should register data formatters like that:

它的内置数据类型工作的通知(localizablemessagenotificationdata和messagenotificationdata)。如果你有自定义通知数据类型,那么你应该登记,数据格式化:

abp.notifications.messageFormatters['MyProject.MyNotificationDataType'] = function(userNotification) {
return ...; //format and return message here
};

Thus, showUiNotifyForUserNotification can create shown messages for your data types. If you just need to the formatted message, you can directly useabp.notifications.getFormattedMessageFromUserNotification(userNotification) which is internally used by showUiNotifyForUserNotification.

Startup templates include the code to show UI notifications when a push notification is received.

Notification Store

Notification system uses INotificationStore to persist notifications. This should be implemented in order to make notification system properly working. You can implement it yourself or use module-zero which already implements it.

系统采用inotificationstore坚持通知的通知。为了使通知系统正常工作,应该实现这一点。您可以自己实现它,也可以使用已经实现它的module-zero

Notification Definitions(通知定义)

You don't have to define a notification before usage. You can just use any notification name without defining it. But, defining it may bring you some additional benefits. For example, you can then investigate all notifications in your application. In this case, we can define a notification provider for our module as shown below:

使用前不必定义通知。您可以使用任何通知名称而不定义它。但是,定义它可能会给你带来一些额外的好处。例如,您可以调查应用程序中的所有通知。在这种情况下,我们可以为我们的模块定义一个通知提供者,如下所示:

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")
)
);
}
}

"App.NewUserRegistered" is unique name of the notification. We defined a localizable displayName (then we can show it while subscribing to the notification on UI). And finally, we declared that this notification is available to a user only if he has "App.Pages.UserManagement" permission.

There are also some other parameters, you can investigate in the code. Only notification name is required for a notification definition.

After defining such a notification provider, we should register it in PreInitialize event of our module, as shown below:

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

Finally, you can inject and use INotificationDefinitionManager in your application to get notification definitions. Then you may want to prepare a automatic page to allow user to subscribe those notifications.

最后,你可以注入和获取通知定义应用程序中使用inotificationdefinitionmanager。然后,您可能需要准备一个自动页面,允许用户订阅这些通知。

ABP框架系列之四十:(Notification-System-通知系统)的更多相关文章

  1. ABP框架系列之四十九:(Startup-Configuration-启动配置)

    ASP.NET Boilerplate provides an infrastructure and a model to configure it and modules on startup. A ...

  2. ABP框架系列之四十六:(Setting-Management-设置管理)

    Introduction Every application need to store some settings and use these settings in somewhere in th ...

  3. ABP框架系列之四十五:(Quartz-Integration-Quartz-集成)

    Introduction Quartz is a is a full-featured, open source job scheduling system that can be used from ...

  4. ABP框架系列之四十四:(OWIN)

    If you are using both of ASP.NET MVC and ASP.NET Web API in your application, you need to add Abp.Ow ...

  5. ABP框架系列之四十二:(Object-To-Object-Mapping-对象映射)

    Introduction It's a common to map a similar object to another object. It's also tedious and repeatin ...

  6. ABP框架系列之四十八:(Specifications-规范)

    Introduction Specification pattern is a particular software design pattern, whereby business rules c ...

  7. ABP框架系列之三十四:(Multi-Tenancy-多租户)

    What Is Multi Tenancy? "Software Multitenancy refers to a software architecture in which a sing ...

  8. ABP框架系列之五十四:(XSRF-CSRF-Protection-跨站请求伪造保护)

    Introduction "Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a maliciou ...

  9. ABP框架系列之四十七:(SignalR-Integration-SignalR-集成)

    Introduction Abp.Web.SignalR nuget package makes it easily to use SignalR in ASP.NET Boilerplate bas ...

随机推荐

  1. python基础之数字、字符串、列表、元组、字典

    Python基础二: 1.运算符: 判断某个东西是否在某个东西里面包含: in  为真 not in  为假 (1).算术运算符: 运算符 描述 实例 + 加  表示两个对象相加 a + b输出结果3 ...

  2. JVM-字节码

  3. OOM问题定位

      一:堆内存溢出 Java创建的对象一般都是分配在堆中,如果是由于过期对象没能回收(内存泄漏)或者对象过多导致放不下(内存溢出),一般报错: Exception in thread \"m ...

  4. [持续交付实践] pipeline使用:项目样例

    项目说明 本文将以一个微服务项目的具体pipeline样例进行脚本编写说明.一条完整的pipeline交付流水线通常会包括代码获取.单元测试.静态检查.打包部署.接口层测试.UI层测试.性能专项测试( ...

  5. sourcetree合并分支

    参考: https://blog.csdn.net/qq_34975710/article/details/74469068

  6. Mybatis-PageHelper分页插件

    PageHelper.startPage 静态方法调用 除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法. 在你需要进行分页 ...

  7. spring-AOP之通知和顾问

    通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能. 而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点. 通知分为前置通知,环绕通知及后置通知 ...

  8. Python代码的人机大战(循环嵌套)

    第一次动手写随笔,记录一下今早的1.5小时努力成果 题目是这样的 : 人和机器进行猜拳游戏写成一个类,首先选择角色:1 曹操 2张飞 3 刘备,然后选择的角色进行猜拳:1剪刀 2石头 3布 玩家输入一 ...

  9. springmvc shiro UnauthorizedException 异常解决方案

    springMVC 整合 shiro 时,配置了当访问某个URL没有权限时的配置处理: <!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 --><propert ...

  10. 即时通信 选择UDP还是TCP协议

    之前做过局域网的聊天软件,现在要做运行在广域网的聊天软件.开始接触网络编程,首先是接触到TCP和UDP协议 在网上查资料,都是这样描述 TCP面向连接,可靠,数据流 .UDP无连接,不可靠,数据报.但 ...