文檔目錄
本節內容:
簡介
通知用來告知用戶系統裡特定的事件發生了,ABP提供一個發布/訂閱,它基於實時通知基礎框架。
發送模式
有兩種方式可以發送通知給用戶:
通知類型
有兩種通知類型:
通知數據
一個通知通常包含一個通知數據,例如:“如果一個用戶發送一個好友請求,那麼通知我”該通知可能有兩個數據屬性:發送者名字(誰發送了這個好友請求)和備注(發送者寫在請求裡的信息),很明顯,通知數據類型與通知類型是緊密聯系的,不同的通知類型有不同的數據類型。
通知數據是可選的,有些通知可能就不需要數據。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": 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" }
在這個對象裡:
當然,你不會只是日志這個通知,你可以使用通知數據把通知信息顯示給用戶,例如:
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