Browse Source

增强通知功能,增加通知生命周期

pull/7/head
cKey 6 years ago
parent
commit
5366b2909d
  1. 6
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs
  2. 18
      aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs
  3. 8
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs
  4. 37
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs
  5. 6
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs
  6. 2
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationEventData.cs
  7. 3
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs
  8. 18
      aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationLifetime.cs
  9. 4
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/AbpMessageServiceNotificationDefinitionProvider.cs
  10. 5
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs
  11. 2
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs
  12. 6
      aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs
  13. 7
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs
  14. 7
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Notifications/MessageServiceDefinitionProvider.cs

6
aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublishProvider.cs

@ -4,6 +4,7 @@ using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LINGYUN.Abp.Notifications.SignalR namespace LINGYUN.Abp.Notifications.SignalR
@ -31,22 +32,23 @@ namespace LINGYUN.Abp.Notifications.SignalR
{ {
// 返回标准数据给前端 // 返回标准数据给前端
notification.Data = NotificationData.ToStandardData(notification.Data); notification.Data = NotificationData.ToStandardData(notification.Data);
foreach (var identifier in identifiers) foreach (var identifier in identifiers)
{ {
Logger.LogDebug($"Find online client with user {identifier.UserId} - {identifier.UserName}");
var onlineClientContext = new OnlineClientContext(notification.TenantId, identifier.UserId); var onlineClientContext = new OnlineClientContext(notification.TenantId, identifier.UserId);
var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext);
foreach (var onlineClient in onlineClients) foreach (var onlineClient in onlineClients)
{ {
try try
{ {
Logger.LogDebug($"Find online client {onlineClient.UserId} - {onlineClient.ConnectionId}");
var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId);
if (signalRClient == null) if (signalRClient == null)
{ {
Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!");
continue; continue;
} }
Logger.LogDebug($"Found a singalr client, begin senging notifications");
await signalRClient.SendAsync("getNotification", notification); await signalRClient.SendAsync("getNotification", notification);
} }
catch (Exception ex) catch (Exception ex)

18
aspnet-core/modules/common/LINGYUN.Abp.Notifications.WeChat/LINGYUN/Abp/Notifications/WeChat/WeApp/WeChatWeAppNotificationSender.cs

@ -1,4 +1,6 @@
using LINGYUN.Abp.WeChat.Authorization; using LINGYUN.Abp.WeChat.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
@ -13,6 +15,7 @@ namespace LINGYUN.Abp.Notifications.WeChat.WeApp
public class WeChatWeAppNotificationSender : IWeChatWeAppNotificationSender, ITransientDependency public class WeChatWeAppNotificationSender : IWeChatWeAppNotificationSender, ITransientDependency
{ {
public const string SendNotificationClientName = "WeChatWeAppSendNotificationClient"; public const string SendNotificationClientName = "WeChatWeAppSendNotificationClient";
public ILogger<WeChatWeAppNotificationSender> Logger { get; set; }
protected IHttpClientFactory HttpClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; }
protected IJsonSerializer JsonSerializer { get; } protected IJsonSerializer JsonSerializer { get; }
protected IWeChatTokenProvider WeChatTokenProvider { get; } protected IWeChatTokenProvider WeChatTokenProvider { get; }
@ -24,6 +27,8 @@ namespace LINGYUN.Abp.Notifications.WeChat.WeApp
JsonSerializer = jsonSerializer; JsonSerializer = jsonSerializer;
HttpClientFactory = httpClientFactory; HttpClientFactory = httpClientFactory;
WeChatTokenProvider = weChatTokenProvider; WeChatTokenProvider = weChatTokenProvider;
Logger = NullLogger<WeChatWeAppNotificationSender>.Instance;
} }
public virtual async Task SendAsync(WeChatWeAppSendNotificationData notificationData) public virtual async Task SendAsync(WeChatWeAppSendNotificationData notificationData)
@ -38,7 +43,14 @@ namespace LINGYUN.Abp.Notifications.WeChat.WeApp
var requestUrl = BuildRequestUrl(weChatSendNotificationUrl, weChatSendNotificationPath, requestParamters); var requestUrl = BuildRequestUrl(weChatSendNotificationUrl, weChatSendNotificationPath, requestParamters);
var responseContent = await MakeRequestAndGetResultAsync(requestUrl, notificationData); var responseContent = await MakeRequestAndGetResultAsync(requestUrl, notificationData);
var weChatSenNotificationResponse = JsonSerializer.Deserialize<WeChatSendNotificationResponse>(responseContent); var weChatSenNotificationResponse = JsonSerializer.Deserialize<WeChatSendNotificationResponse>(responseContent);
weChatSenNotificationResponse.ThrowIfNotSuccess();
if (!weChatSenNotificationResponse.IsSuccessed)
{
Logger.LogWarning("Send wechat we app subscribe message failed");
Logger.LogWarning($"Error code: {weChatSenNotificationResponse.ErrorCode}, message: {weChatSenNotificationResponse.ErrorMessage}");
}
// 失败是否抛出异常
// weChatSenNotificationResponse.ThrowIfNotSuccess();
} }
protected virtual async Task<string> MakeRequestAndGetResultAsync(string url, WeChatWeAppSendNotificationData notificationData) protected virtual async Task<string> MakeRequestAndGetResultAsync(string url, WeChatWeAppSendNotificationData notificationData)
{ {
@ -53,7 +65,7 @@ namespace LINGYUN.Abp.Notifications.WeChat.WeApp
var response = await client.SendAsync(requestMessage); var response = await client.SendAsync(requestMessage);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
throw new AbpException($"Baidu http request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}"); throw new AbpException($"WeChat send subscribe message http request service returns error! HttpStatusCode: {response.StatusCode}, ReasonPhrase: {response.ReasonPhrase}");
} }
var resultContent = await response.Content.ReadAsStringAsync(); var resultContent = await response.Content.ReadAsStringAsync();
@ -83,6 +95,8 @@ namespace LINGYUN.Abp.Notifications.WeChat.WeApp
[JsonProperty("errmsg")] [JsonProperty("errmsg")]
public string ErrorMessage { get; set; } public string ErrorMessage { get; set; }
public bool IsSuccessed => ErrorCode == 0;
public void ThrowIfNotSuccess() public void ThrowIfNotSuccess()
{ {
if (ErrorCode != 0) if (ErrorCode != 0)

8
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationDispatcher.cs

@ -8,14 +8,6 @@ namespace LINGYUN.Abp.Notifications
/// </summary> /// </summary>
public interface INotificationDispatcher public interface INotificationDispatcher
{ {
/// <summary>
/// 发送通知
/// </summary>
/// <param name="notification"></param>
/// <returns></returns>
[Obsolete("Api已过时,请调用 DispatcheAsync(string notificationName, NotificationData data, Guid? tenantId = null)")]
Task DispatchAsync(NotificationInfo notification);
/// <summary> /// <summary>
/// 发送通知 /// 发送通知
/// </summary> /// </summary>

37
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs

@ -84,6 +84,7 @@ namespace LINGYUN.Abp.Notifications.Internal
Name = notificationName.Name, Name = notificationName.Name,
CreationTime = DateTime.Now, CreationTime = DateTime.Now,
NotificationSeverity = notificationSeverity, NotificationSeverity = notificationSeverity,
Lifetime = defineNotification.NotificationLifetime,
NotificationType = defineNotification.NotificationType, NotificationType = defineNotification.NotificationType,
TenantId = tenantId, TenantId = tenantId,
Data = data Data = data
@ -98,6 +99,13 @@ namespace LINGYUN.Abp.Notifications.Internal
} }
await PublishFromProvidersAsync(providers, notificationInfo); await PublishFromProvidersAsync(providers, notificationInfo);
if (notificationInfo.Lifetime == NotificationLifetime.OnlyOne)
{
// 一次性通知在发送完成后就取消用户订阅
await _notificationStore.DeleteAllUserSubscriptionAsync(notificationInfo.TenantId,
notificationInfo.Name);
}
} }
/// <summary> /// <summary>
/// 发送通知事件 /// 发送通知事件
@ -119,6 +127,7 @@ namespace LINGYUN.Abp.Notifications.Internal
Name = notificationName.Name, Name = notificationName.Name,
CreationTime = DateTime.Now, CreationTime = DateTime.Now,
NotificationSeverity = notificationSeverity, NotificationSeverity = notificationSeverity,
Lifetime = defineNotification.NotificationLifetime,
NotificationType = defineNotification.NotificationType, NotificationType = defineNotification.NotificationType,
TenantId = tenantId, TenantId = tenantId,
Data = data Data = data
@ -126,34 +135,6 @@ namespace LINGYUN.Abp.Notifications.Internal
// 发布分布式通知事件,让消息中心统一处理 // 发布分布式通知事件,让消息中心统一处理
await DistributedEventBus.PublishAsync(notificationEventData); await DistributedEventBus.PublishAsync(notificationEventData);
} }
/// <summary>
/// 发送通知
/// </summary>
/// <param name="notification">通知信息</param>
/// <returns></returns>
public virtual async Task DispatchAsync(NotificationInfo notification)
{
// 获取自定义的通知
var defineNotification = _notificationDefinitionManager.GetOrNull(notification.Name);
// 没有定义的通知,应该也要能发布、订阅,
// 比如订单之类的,是以订单编号为通知名称,这是动态的,没法自定义
if (defineNotification == null)
{
defineNotification = new NotificationDefinition(notification.Name);
}
var providers = Enumerable
.Reverse(_notificationPublishProviderManager.Providers);
if (defineNotification.Providers.Any())
{
providers = providers.Where(p => defineNotification.Providers.Contains(p.Name));
}
await PublishFromProvidersAsync(providers, notification);
}
/// <summary> /// <summary>
/// 指定提供者发布通知 /// 指定提供者发布通知
/// </summary> /// </summary>

6
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationDefinition.cs

@ -40,6 +40,10 @@ namespace LINGYUN.Abp.Notifications
/// </summary> /// </summary>
public bool AllowSubscriptionToClients { get; set; } public bool AllowSubscriptionToClients { get; set; }
/// <summary> /// <summary>
/// 存活类型
/// </summary>
public NotificationLifetime NotificationLifetime { get; set; }
/// <summary>
/// 通知类型 /// 通知类型
/// </summary> /// </summary>
public NotificationType NotificationType { get; set; } public NotificationType NotificationType { get; set; }
@ -53,11 +57,13 @@ namespace LINGYUN.Abp.Notifications
ILocalizableString displayName = null, ILocalizableString displayName = null,
ILocalizableString description = null, ILocalizableString description = null,
NotificationType notificationType = NotificationType.Application, NotificationType notificationType = NotificationType.Application,
NotificationLifetime lifetime = NotificationLifetime.Persistent,
bool allowSubscriptionToClients = false) bool allowSubscriptionToClients = false)
{ {
CateGory = category; CateGory = category;
DisplayName = displayName ?? new FixedLocalizableString(category); DisplayName = displayName ?? new FixedLocalizableString(category);
Description = description; Description = description;
NotificationLifetime = lifetime;
NotificationType = notificationType; NotificationType = notificationType;
AllowSubscriptionToClients = allowSubscriptionToClients; AllowSubscriptionToClients = allowSubscriptionToClients;

2
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationEventData.cs

@ -10,6 +10,7 @@ namespace LINGYUN.Abp.Notifications
public string Id { get; set; } public string Id { get; set; }
public NotificationData Data { get; set; } public NotificationData Data { get; set; }
public DateTime CreationTime { get; set; } public DateTime CreationTime { get; set; }
public NotificationLifetime Lifetime { get; set; }
public NotificationType NotificationType { get; set; } public NotificationType NotificationType { get; set; }
public NotificationSeverity NotificationSeverity { get; set; } public NotificationSeverity NotificationSeverity { get; set; }
@ -29,6 +30,7 @@ namespace LINGYUN.Abp.Notifications
Name = Name, Name = Name,
CateGory = CateGory, CateGory = CateGory,
NotificationType = NotificationType, NotificationType = NotificationType,
Lifetime = Lifetime,
TenantId = TenantId TenantId = TenantId
}; };
} }

3
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs

@ -10,11 +10,13 @@ namespace LINGYUN.Abp.Notifications
public string Id { get; set; } public string Id { get; set; }
public NotificationData Data { get; set; } public NotificationData Data { get; set; }
public DateTime CreationTime { get; set; } public DateTime CreationTime { get; set; }
public NotificationLifetime Lifetime { get; set; }
public NotificationType NotificationType { get; set; } public NotificationType NotificationType { get; set; }
public NotificationSeverity NotificationSeverity { get; set; } public NotificationSeverity NotificationSeverity { get; set; }
public NotificationInfo() public NotificationInfo()
{ {
Data = new NotificationData(); Data = new NotificationData();
Lifetime = NotificationLifetime.Persistent;
NotificationType = NotificationType.Application; NotificationType = NotificationType.Application;
NotificationSeverity = NotificationSeverity.Info; NotificationSeverity = NotificationSeverity.Info;
@ -47,6 +49,7 @@ namespace LINGYUN.Abp.Notifications
Id = Id, Id = Id,
Name = Name, Name = Name,
CateGory = CateGory, CateGory = CateGory,
Lifetime = Lifetime,
NotificationType = NotificationType, NotificationType = NotificationType,
TenantId = TenantId TenantId = TenantId
}; };

18
aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationLifetime.cs

@ -0,0 +1,18 @@
namespace LINGYUN.Abp.Notifications
{
/// <summary>
/// 通知存活时间
/// 发送之后取消用户订阅,类似于微信小程序
/// </summary>
public enum NotificationLifetime
{
/// <summary>
/// 持久化
/// </summary>
Persistent = 0,
/// <summary>
/// 一次性
/// </summary>
OnlyOne = 1
}
}

4
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/AbpMessageServiceNotificationDefinitionProvider.cs

@ -14,11 +14,15 @@ namespace LINGYUN.Abp.MessageService.Notifications
UserNotificationNames.WelcomeToApplication, UserNotificationNames.WelcomeToApplication,
L("WelcomeToApplicationNotification"), L("WelcomeToApplicationNotification"),
L("WelcomeToApplicationNotification"), L("WelcomeToApplicationNotification"),
notificationType: NotificationType.System,
lifetime: NotificationLifetime.OnlyOne,
allowSubscriptionToClients: true)); allowSubscriptionToClients: true));
context.Add(new NotificationDefinition( context.Add(new NotificationDefinition(
TenantNotificationNames.NewTenantRegistered, TenantNotificationNames.NewTenantRegistered,
L("NewTenantRegisterdNotification"), L("NewTenantRegisterdNotification"),
L("NewTenantRegisterdNotification"), L("NewTenantRegisterdNotification"),
notificationType: NotificationType.System,
lifetime: NotificationLifetime.OnlyOne,
allowSubscriptionToClients: true)); allowSubscriptionToClients: true));
} }

5
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs

@ -95,9 +95,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
using (var unitOfWork = _unitOfWorkManager.Begin()) using (var unitOfWork = _unitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId)) using (CurrentTenant.Change(tenantId))
{ {
var userSubscribes = await UserSubscribeRepository.GetSubscribesAsync(notificationName); await UserSubscribeRepository.DeleteUserSubscriptionAsync(notificationName);
await UserSubscribeRepository.DeleteUserSubscriptionAsync(userSubscribes);
await unitOfWork.SaveChangesAsync(); await unitOfWork.SaveChangesAsync();
} }
@ -122,6 +120,7 @@ namespace LINGYUN.Abp.MessageService.Notifications
using (var unitOfWork = _unitOfWorkManager.Begin()) using (var unitOfWork = _unitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId)) using (CurrentTenant.Change(tenantId))
{ {
// TODO:不追踪用户订阅实体?
var userSubscribes = await UserSubscribeRepository.GetSubscribesAsync(notificationName); var userSubscribes = await UserSubscribeRepository.GetSubscribesAsync(notificationName);
var removeUserSubscribes = userSubscribes.Where(us => identifiers.Any(id => id.UserId.Equals(us.UserId))); var removeUserSubscribes = userSubscribes.Where(us => identifiers.Any(id => id.UserId.Equals(us.UserId)));

2
aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs

@ -22,5 +22,7 @@ namespace LINGYUN.Abp.MessageService.Subscriptions
Task InsertUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes); Task InsertUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes);
Task DeleteUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes); Task DeleteUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes);
Task DeleteUserSubscriptionAsync(string notificationName);
} }
} }

6
aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs

@ -78,6 +78,12 @@ namespace LINGYUN.Abp.MessageService.Subscriptions
await DbSet.AddRangeAsync(userSubscribes); await DbSet.AddRangeAsync(userSubscribes);
} }
public async Task DeleteUserSubscriptionAsync(string notificationName)
{
var userSubscribes = await DbSet.Where(x => x.NotificationName.Equals(notificationName)).ToListAsync();
DbSet.RemoveRange(userSubscribes);
}
public Task DeleteUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes) public Task DeleteUserSubscriptionAsync(IEnumerable<UserSubscribe> userSubscribes)
{ {
DbSet.RemoveRange(userSubscribes); DbSet.RemoveRange(userSubscribes);

7
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/EventBus/Distributed/NotificationEventHandler.cs

@ -96,6 +96,13 @@ namespace LINGYUN.Abp.MessageService.EventBus.Distributed
{ {
await PublishAsync(provider, notificationInfo, subscriptionUserIdentifiers); await PublishAsync(provider, notificationInfo, subscriptionUserIdentifiers);
} }
if (notificationInfo.Lifetime == NotificationLifetime.OnlyOne)
{
// 一次性通知在发送完成后就取消用户订阅
await NotificationStore.DeleteAllUserSubscriptionAsync(notificationInfo.TenantId,
notificationInfo.Name);
}
} }
/// <summary> /// <summary>
/// 发布通知 /// 发布通知

7
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Notifications/MessageServiceDefinitionProvider.cs

@ -2,7 +2,7 @@
using LINGYUN.Abp.Notifications; using LINGYUN.Abp.Notifications;
using Volo.Abp.Localization; using Volo.Abp.Localization;
namespace LINGYUN.Abp.MessageService.LINGYUN.Abp.MessageService.Notifications namespace LINGYUN.Abp.MessageService.Notifications
{ {
public class MessageServiceDefinitionProvider : NotificationDefinitionProvider public class MessageServiceDefinitionProvider : NotificationDefinitionProvider
{ {
@ -12,8 +12,9 @@ namespace LINGYUN.Abp.MessageService.LINGYUN.Abp.MessageService.Notifications
"TestApplicationNotofication", "TestApplicationNotofication",
L("TestApplicationNotofication"), L("TestApplicationNotofication"),
L("TestApplicationNotofication"), L("TestApplicationNotofication"),
NotificationType.Application, notificationType: NotificationType.Application,
true)); lifetime: NotificationLifetime.OnlyOne,
allowSubscriptionToClients: true));
} }
protected LocalizableString L(string name) protected LocalizableString L(string name)

Loading…
Cancel
Save