X-Admin&ABP框架開發-訊息通知

微笑刺客D發表於2019-07-27

  業務型網站使用過程中,訊息通知是一個不可或缺的功能,採用站內通知、簡訊通知、郵件通知、微信通知等等各種方式都有,ABP框架對這部分工作已經封裝的很好了,站在巨人的肩膀上,一覽全貌,帶來的就是心情舒暢。

   ABP官網地址:https://aspnetboilerplate.com/

 

一、明確概念及設計

  一次完整的訊息傳送/接收過程中,會存在幾個必要的點,也正如同現實生活中的場景,有人傳送,有人接收,傳送的訊息本身也有型別。

  

1、訊息型別定義

   在ABP中已經提供了訊息型別定義的相關類,但是需要我們去實現,在領域層新建一個Notifications資料夾並新增一個定義常用訊息型別名稱的靜態類如AppNotificationNames(名稱可隨意),在其中開始定義訊息型別名稱。

/// <summary>
/// 設定應用程式中常用通知唯一的名稱常量
/// </summary>
public static class AppNotificationNames
{
    #region 新的任務
    public const string NewTask = "App.NewTask";
    #endregion

    #region 簡單訊息
    public const string SimpleMessage = "App.SimpleMessage";
    #endregion
}

   其次,開始訊息型別定義,新建一個NotificationProvider的類,完成訊息型別定義,管理訊息型別時,可以針對訊息設定許可權,這樣方便不同的角色擁有不同的訊息通知。

/// <summary>
/// 訊息型別定義
/// </summary>
public class AppNotificationProvider : NotificationProvider
{
    /// <summary>
    /// 設定訊息型別
    /// </summary>
    /// <param name="context"></param>
    public override void SetNotifications(INotificationDefinitionContext context)
    {
        #region 任務提醒
        context.Manager.Add(
            new NotificationDefinition(
                AppNotificationNames.NewTask,
                displayName: L("NewTask"),
                permissionDependency: new SimplePermissionDependency(PermissionNames.Pages_TaskManage)
            )
        );
        #endregion
    }

    private static ILocalizableString L(string name)
    {
        return new LocalizableString(name, SurroundConsts.LocalizationSourceName);
    }
}

   最後在領域層的Module.PreInitialize()中完成加入。

//通知定義
Configuration.Notifications.Providers.Add<AppNotificationProvider>();

 

2、訊息訂閱方式

  對於訊息訂閱環節,是存在兩種情形的,第一種,傳送方發出的訊息,可以指定所有訂閱了的人員接收,比如,只有擁有任務管理許可權的人才會接收到新的任務下發的通知;第二種就是指定到具體人員接收,比如檔案上傳完畢的訊息通知是通知到負責檔案上傳的人。

   

   訊息訂閱的管理,在ABP框架中已經封裝好了,我們可以通過建構函式注入直接使用,通過獲取系統內的提前定義的所有訊息型別,我們可以在介面上完成訂閱工作,為當前使用者訂閱在他角色許可權內的訊息通知及無許可權限制的訊息通知等。

private readonly INotificationDefinitionManager _notificationDefinitionManager;
private readonly INotificationSubscriptionManager _notificationSubscriptionManager;

public NotificationAppService(
    INotificationDefinitionManager notificationDefinitionManager,
    INotificationSubscriptionManager notificationSubscriptionManager)
{
    _notificationDefinitionManager = notificationDefinitionManager;
    _notificationSubscriptionManager = notificationSubscriptionManager;
}

 

3、訊息釋出方式

  

  訊息釋出時,可以是嵌入在其它操作中,比如制定完成一個新的任務後,傳送訊息給相關人員,或是在檔案上傳完畢後,傳送給檔案上傳人員,也可以是定時任務中,指定時間點傳送訊息,對於這部分來講,在領域層建立一個訊息通知的類,來負責處理訊息通知,而具體實現訊息通知的過程ABP框架中已經實現了,如同訊息訂閱一樣,只需要在建構函式中注入即可,其次定義具體的訊息傳送方法,使得具體操作結束後呼叫具體的訊息傳送來傳送訊息。

/// <summary>
/// 訊息通知釋出例項
/// </summary>
public class AppNotifier : DomainService, IAppNotifier
{
    #region 初始化
    private readonly INotificationPublisher _notificationPublisher;

    public AppNotifier(INotificationPublisher notificationPublisher)
    {
        _notificationPublisher = notificationPublisher;
    }
    #endregion

    #region 訊息傳送
    public async Task SendMessageAsync(UserIdentifier user, string message, NotificationSeverity severity = NotificationSeverity.Info)
    {
        await _notificationPublisher.PublishAsync(
            AppNotificationNames.SimpleMessage,
            new MessageNotificationData(message),
            severity: severity,
            userIds: new[] { user }
        );
    }
    #endregion

    #region 任務提醒
    public async Task NewTaskAsync(string message, NotificationSeverity severity = NotificationSeverity.Info)
    {
        await PublishMessage(AppNotificationNames.NewTask, message);
    }
    #endregion

    #region 輔助方法
    private async Task PublishMessage(string appNotificationName, string message)
    {
        await _notificationPublisher.PublishAsync(appNotificationName, new MessageNotificationData(message));
    }
    #endregion
}

 

二、完成使用者訂閱訊息

   在MVC層,在使用者控制器中完成對訊息通知設定,訊息本身是獨立的,只應有了使用者才活躍起來,因此把訊息的設定掛鉤在使用者身上,應該算是合理的,並同時完成頁面的設計。

/// <summary>
/// 通知設定
/// </summary>
/// <returns></returns>
public async Task<ActionResult> NotificationSetting()
{
    var notificationSettings = await _notificationAppService.GetNotificationSettings();
    return View(notificationSettings);
}

/// <summary>
/// 更新通知訂閱
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<JsonResult> UpdateNotificationSetting([FromBody]UpdateNotificationSettingsInput input)
{
    await _notificationAppService.UpdateNotificationSettings(input);
    return Json(new ResponseParamViewModel("通知設定已更新"));
}

   頁面設計只需要對提前在領域層中定義好的訊息型別展示出來即可,使用者自主勾選哪些想要接收的訊息提示。

  

 

三、釋出訊息通知使用者

  在指定操作完畢,可以呼叫訊息服務來推送訊息到目標接收人員,此處,更改了原先資料字典建立處的程式碼,當建立資料字典成功後,給與一個訊息提示來模擬釋出訊息通知使用者的過程。

var existedDataDictionary = await _dataDictionaryRepository.GetAll().Where(d => d.TypeName == input.DataDictionary.TypeName).FirstOrDefaultAsync();

if (existedDataDictionary != null)
{
    throw new UserFriendlyException(L("該字典型別已存在,無法新增"));
}

var dataDictionary = ObjectMapper.Map<DataDictionary>(input.DataDictionary);
await _dataDictionaryRepository.InsertAsync(dataDictionary);

//模擬測試訊息通知
await _appNotifier.NewTaskAsync("字典型別已完成新增,可以開始使用了");

   該訊息觸發的前提是,需要訂閱該訊息,不然有人發,無人收,總是很難為情。因此提前在通知設定中開啟型別為“新的任務”的開關。

  

  對於訊息傳送到了瀏覽器中呈現,這個過程採用了SignalR,ABP框架也完成了前後端的訊息通知,因此可以直接使用即可。

 

  至此,站內訊息通知的設計完畢,對於業務需求中可能面對的更為豐富的功能就得花更多時間來完成了。 

  程式碼地址:https://gitee.com/530521314/Partner.Surround.git

 

2019-07-27,望技術有成後能回來看見自己的腳步

相關文章