通知系统

介绍

通知用于通知用户系统中的特定事件。ASP.NET Boilerplate提供基于发布/订阅(发布/订阅)的实时通知系统。

发送模型

有两种向用户发送通知的方法:

通知类型

还有两种类型的通知:

通知数据

通知通常包括通知数据。例如:“如果用户向我发送友情请求通知我”通知可能有两个数据属性:  发件人用户名  (用户发送此友情请求)和  请求备注  (用户在请求中写入的备注)。请注意,通知数据类型与通知类型紧密耦合。不同的通知类型具有不同的数据类型

通知数据是可选的。某些通知可能不需要数据。有一些预定义的通知数据类型足以满足大多数情况。MessageNotificationData可用于简单消息,LocalizableMessageNotificationData可用于可本地化和参数化通知消息。我们将在后面的部分中看到示例用法。

通知严重性

通知严重性有5个级别,在NotificationSeverity枚举中定义:信息,成功,警告,错误和致命。默认值为Info。

关于通知持久性

有关 通知持久性的详细信息,请参阅“  通知存储”部分。

订阅通知

INotificationSubscriptionManager提供了一个API来订阅通知。例子:

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

首先,我们  注入  了INotificationSubscriptionManager。如果用户想要在有人发送友谊请求时得到通知,则第一种方法订阅一般通知。第二种方法订阅与特定实体(Photo)相关的通知,如果用户想要通知任何人是否有人将评论写入指定照片。

每种通知类型都应具有唯一的名称(如  示例中的SentFrendshipRequest  和  CommentPhoto  )

INotificationSubscriptionManager还具有UnsubscribeAsync,IsSubscribedAsAsync,GetSubscriptionsAsync ...方法来管理订阅。

发布通知

INotificationPublisher用于发布通知。例子:

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

在第一个示例中,我们向单个用户发布了通知。 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序列化)。但我们建议您将其标记为可序列化,因为您可能需要在应用程序之间移动通知,并且可能希望将来使用二进制序列化。此外,如前所述,通知数据是可选的,并非所有通知都需要。

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

在第三个示例中,我们没有定义专用通知数据类。相反,我们直接将内置的LocalMessageNotificationData与基于字典的数据一起使用,然后将通知发布为“警告”。LocalizableMessageNotificationData可以存储基于字典的任意数据(对于自定义通知数据类也是如此,因为它们也从NotificationData类继承)。我们使用“remainingDiskInMb”作为本地化的参数  本地化消息可以包括这些参数(例如“ 注意!仅剩下磁盘上剩余的{remainingDiskInMb} MB! ”作为示例)。我们将看到如何在客户端部分本地化它。

用户通知管理器

IUserNotificationManager用于管理用户的通知。它具有获取,更新或删除用户通知的方法。您可以使用它为您的应用程序准备通知列表页面。

实时通知

虽然您可以使用IUserNotificationManager查询通知,但我们通常希望将实时通知推送到客户端。

通知系统使用IRealTimeNotifier向用户发送实时通知。这可以用任何类型的实时通信系统来实现。它是在一个独立的包中使用SignalR实现的。在  启动模板  已安装SignalR。有关 更多信息,请参阅  SignalR集成文档

注意:通知系统在后台作业中异步调用IRealTimeNotifier  因此,可能会以很小的延迟发送通知。

客户端

收到实时通知后,ASP.NET Boilerplate会在客户端触发全局事件。您可以像这样注册以获取通知:

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 ...; //format and return message here
};

这样,showUiNotifyForUserNotification可以为您的数据类型创建显示的消息。如果您只需要格式化消息,则可以直接使用showUiNotifyForUserNotification内部使用的abp.notifications.getFormattedMessageFromUserNotification(userNotification)。

在  启动模板  包含代码收到一个推送通知时,显示的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")
                )
            );
    }
}

“App.NewUserRegistered”是通知的唯一名称。我们定义了一个可本地化的displayName,以便我们可以在订阅UI上的通知时显示它。最后,我们声明只有拥有“App.Pages.UserManagement” 权限的用户才能使用此通知  

您还可以在代码中调查其他一些参数。注意:通知定义需要通知名称。

在定义了这样的通知提供程序之后,我们必须在 我们模块PreInitialize方法中注册它  ,如下所示:

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

    //...
}

最后,您可以在应用程序中注入并使用INotificationDefinitionManager来获取通知定义。然后,您可能希望准备一个自动页面,以允许用户订阅这些通知。

nidie.com.cn - 用心与你沟通