Notifications are used to inform users on specific events in the system. ASP.NET Boilerplate provides a pub/sub based real time notification infrastructure.javascript
通知用於通知用戶系統中的特定事件。ASP.NET的模板提供了一個基於實時通知基建Pub/Sub。java
There are two ways of sending notifications to users:api
There are also two types of notifications:session
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.app
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.async
通知數據是可選的。有些通知可能不須要數據。有一些預約義的通知數據類型,大多數狀況下這些數據類型是足夠的。messagenotificationdata能夠用於簡單的消息和localizablemessagenotificationdata可用於定位和參數的通知消息。咱們將在後面的部分中看到示例用法。ide
There are 5 levels of notification severity, defined in NotificationSeverity enum: Info, Success, Warn, Error and Fatal. Default value is Info.ui
See Notification Store section for more information on notification persistence.this
INotificationSubscriptionManager provides API to subscribe to notifications. Examples:spa
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.
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!」在例子中)。咱們將看到如何在客戶端部分本地化它。
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.
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.
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;
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 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。
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。而後,您可能須要準備一個自動頁面,容許用戶訂閱這些通知。