37 changed files with 319 additions and 252 deletions
@ -0,0 +1,11 @@ |
|||
// Global using directives
|
|||
|
|||
global using Lion.AbpPro.SignalR.Enums; |
|||
global using Microsoft.AspNetCore.SignalR; |
|||
global using Microsoft.Extensions.Logging; |
|||
global using Volo.Abp.DependencyInjection; |
|||
global using Volo.Abp.EventBus.Local; |
|||
global using Volo.Abp.Guids; |
|||
global using Volo.Abp.Json; |
|||
global using Volo.Abp.MultiTenancy; |
|||
global using Volo.Abp.Users; |
|||
@ -0,0 +1,15 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net9.0</TargetFramework> |
|||
<RootNamespace /> |
|||
<PackageId>Lion.AbpPro.SignalR</PackageId> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Autofac" /> |
|||
<PackageReference Include="Volo.Abp.Ddd.Domain" /> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.AspNetCore.SignalR; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Lion.AbpPro.SignalR; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpAspNetCoreSignalRModule))] |
|||
public class AbpProNotificationModule : AbpModule |
|||
{ |
|||
} |
|||
@ -1,6 +1,6 @@ |
|||
using System.ComponentModel; |
|||
|
|||
namespace Lion.AbpPro.NotificationManagement.Notifications.Enums; |
|||
namespace Lion.AbpPro.SignalR.Enums; |
|||
|
|||
/// <summary>
|
|||
/// 消息等级
|
|||
@ -1,6 +1,6 @@ |
|||
using System.ComponentModel; |
|||
|
|||
namespace Lion.AbpPro.NotificationManagement.Notifications.Enums |
|||
namespace Lion.AbpPro.SignalR.Enums |
|||
{ |
|||
/// <summary>
|
|||
/// 消息类型
|
|||
@ -0,0 +1,15 @@ |
|||
namespace Lion.AbpPro.SignalR.Hubs |
|||
{ |
|||
public interface INotificationHub |
|||
{ |
|||
/// <summary>
|
|||
/// 接受普通消息
|
|||
/// </summary>
|
|||
Task ReceiveTextMessageAsync(SendNotificationDto message); |
|||
|
|||
/// <summary>
|
|||
/// 接受广播消息
|
|||
/// </summary>
|
|||
Task ReceiveBroadCastMessageAsync(SendNotificationDto message); |
|||
} |
|||
} |
|||
@ -1,10 +1,13 @@ |
|||
namespace Lion.AbpPro.NotificationManagement.Hubs |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Volo.Abp.AspNetCore.SignalR; |
|||
using Volo.Abp.Auditing; |
|||
|
|||
namespace Lion.AbpPro.SignalR.Hubs |
|||
{ |
|||
[HubRoute("SignalR/Notification")] |
|||
[Authorize] |
|||
[DisableAuditing] |
|||
public class NotificationHub : AbpHub<INotificationHub> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
namespace Lion.AbpPro.SignalR; |
|||
|
|||
public interface IMessageManager |
|||
{ |
|||
/// <summary>
|
|||
/// 发送消息
|
|||
/// </summary>
|
|||
/// <param name="title">消息标题</param>
|
|||
/// <param name="content">消息内容</param>
|
|||
/// <param name="messageType">消息类型</param>
|
|||
/// <param name="messageLevel">消息级别</param>
|
|||
/// <param name="receiverUserId">消息接受人,如果是广播消息,不需要传递</param>
|
|||
/// <param name="receiverUserName">消息接受人userName,如果是广播消息,不需要传递</param>
|
|||
/// <param name="isPersistent">是否持久化,如果ture会在消息管理中出现,并且右上角也会存在</param>
|
|||
/// <returns></returns>
|
|||
Task SendMessageAsync(string title, string content, MessageType messageType, MessageLevel messageLevel, Guid? receiverUserId = null, string receiverUserName = "", bool isPersistent = true); |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
namespace Lion.AbpPro.SignalR.LocalEvent.Notification; |
|||
|
|||
/// <summary>
|
|||
/// 创建消息本地事件
|
|||
/// </summary>
|
|||
public class CreatedNotificationLocalEvent |
|||
{ |
|||
public CreatedNotificationLocalEvent(Guid id, Guid? tenantId, string title, string content, MessageType messageType, MessageLevel messageLevel, Guid senderUserId, string senderUserName, Guid? receiveUserId, string receiveUserName, bool isPersistent) |
|||
{ |
|||
Id = id; |
|||
TenantId = tenantId; |
|||
Title = title; |
|||
Content = content; |
|||
MessageType = messageType; |
|||
MessageLevel = messageLevel; |
|||
SenderUserId = senderUserId; |
|||
SenderUserName = senderUserName; |
|||
ReceiveUserId = receiveUserId; |
|||
ReceiveUserName = receiveUserName; |
|||
IsPersistent = isPersistent; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 消息id
|
|||
/// </summary>
|
|||
public Guid Id { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 租户id
|
|||
/// </summary>
|
|||
public Guid? TenantId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息标题
|
|||
/// </summary>
|
|||
public string Title { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
public string Content { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息类型
|
|||
/// </summary>
|
|||
public MessageType MessageType { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息等级
|
|||
/// </summary>
|
|||
public MessageLevel MessageLevel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发送人
|
|||
/// </summary>
|
|||
public Guid SenderUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发送人用户名
|
|||
/// </summary>
|
|||
public string SenderUserName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 订阅人
|
|||
/// 消息类型是广播消息时,订阅人为空
|
|||
/// </summary>
|
|||
public Guid? ReceiveUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 接收人用户名
|
|||
/// 消息类型是广播消息时,订接收人用户名为空
|
|||
/// </summary>
|
|||
public string ReceiveUserName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息是否持久化
|
|||
/// </summary>
|
|||
public bool IsPersistent { get; set; } |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using Lion.AbpPro.SignalR.Hubs; |
|||
using Lion.AbpPro.SignalR.LocalEvent.Notification; |
|||
|
|||
namespace Lion.AbpPro.SignalR; |
|||
|
|||
public class MessageManager : IMessageManager, ITransientDependency |
|||
{ |
|||
private readonly IHubContext<NotificationHub, INotificationHub> _hubContext; |
|||
private readonly ILogger<MessageManager> _logger; |
|||
private readonly ILocalEventBus _localEventBus; |
|||
private readonly ICurrentUser _currentUser; |
|||
private readonly ICurrentTenant _currentTenant; |
|||
private readonly IGuidGenerator _guidGenerator; |
|||
|
|||
public MessageManager(IHubContext<NotificationHub, INotificationHub> hubContext, ILogger<MessageManager> logger, ILocalEventBus localEventBus, ICurrentUser currentUser, ICurrentTenant currentTenant, IGuidGenerator guidGenerator) |
|||
{ |
|||
_hubContext = hubContext; |
|||
_logger = logger; |
|||
_localEventBus = localEventBus; |
|||
_currentUser = currentUser; |
|||
_currentTenant = currentTenant; |
|||
_guidGenerator = guidGenerator; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送消息
|
|||
/// </summary>
|
|||
/// <param name="title">消息标题</param>
|
|||
/// <param name="content">消息内容</param>
|
|||
/// <param name="messageType">消息类型</param>
|
|||
/// <param name="messageLevel">消息级别</param>
|
|||
/// <param name="receiverUserId">消息接受人,如果是广播消息,不需要传递</param>
|
|||
/// <param name="receiverUserName">消息接受人userName,如果是广播消息,不需要传递</param>
|
|||
/// <param name="isPersistent">是否持久化,如果ture会在消息管理中出现,并且右上角也会存在</param>
|
|||
/// <returns></returns>
|
|||
public virtual async Task SendMessageAsync(string title, string content, MessageType messageType, MessageLevel messageLevel, Guid? receiverUserId = null, string receiverUserName = "", bool isPersistent = true) |
|||
{ |
|||
var messageId = _guidGenerator.Create(); |
|||
if (messageType == MessageType.Common) |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(receiverUserId.ToString())) |
|||
{ |
|||
_logger.LogError($"发送消息失败:接收用户ID为空,消息Id:{messageId}"); |
|||
return; |
|||
} |
|||
|
|||
await _hubContext.Clients |
|||
.Users([receiverUserId.ToString()]) |
|||
.ReceiveTextMessageAsync(new SendNotificationDto(messageId, title, content, messageType, messageLevel)); |
|||
} |
|||
|
|||
if (messageType == MessageType.BroadCast) |
|||
{ |
|||
await _hubContext.Clients.All.ReceiveBroadCastMessageAsync(new SendNotificationDto(messageId, title, content, messageType, messageLevel)); |
|||
} |
|||
|
|||
if (isPersistent) |
|||
{ |
|||
await _localEventBus.PublishAsync(new CreatedNotificationLocalEvent(messageId, _currentTenant.Id, title, content, messageType, messageLevel, _currentUser.GetId(), _currentUser.UserName, receiverUserId, receiverUserName, true)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
namespace Lion.AbpPro.SignalR |
|||
{ |
|||
public class SendNotificationDto |
|||
{ |
|||
public Guid Id { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息标题
|
|||
/// </summary>
|
|||
public string Title { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
public string Content { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息类型
|
|||
/// </summary>
|
|||
public MessageType MessageType { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息等级
|
|||
/// </summary>
|
|||
public MessageLevel MessageLevel { get; set; } |
|||
|
|||
private SendNotificationDto() |
|||
{ |
|||
} |
|||
|
|||
public SendNotificationDto(Guid id, string title, string content, MessageType messageType, MessageLevel messageLevel) |
|||
{ |
|||
Id = id; |
|||
Title = title; |
|||
Content = content; |
|||
MessageType = messageType; |
|||
MessageLevel = messageLevel; |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
namespace Lion.AbpPro.NotificationManagement.Hubs |
|||
{ |
|||
public interface INotificationHub |
|||
{ |
|||
/// <summary>
|
|||
/// 发送普通消息
|
|||
/// </summary>
|
|||
/// <param name="input"></param>
|
|||
/// <returns></returns>
|
|||
Task ReceiveTextMessageAsync(SendNotificationDto input); |
|||
|
|||
/// <summary>
|
|||
/// 发送广播消息
|
|||
/// </summary>
|
|||
/// <param name="input"></param>
|
|||
/// <returns></returns>
|
|||
Task ReceiveBroadCastMessageAsync(SendNotificationDto input); |
|||
} |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
namespace Lion.AbpPro.NotificationManagement.Hubs; |
|||
|
|||
public interface INotificationHubAppService : IApplicationService |
|||
{ |
|||
Task SendMessageAsync(Guid id, string title, string content, MessageType messageType,MessageLevel messageLevel, string receiverUserId); |
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
using Volo.Abp.Json; |
|||
|
|||
namespace Lion.AbpPro.NotificationManagement.Hubs; |
|||
|
|||
public class NotificationHubAppService : NotificationManagementAppService, INotificationHubAppService |
|||
{ |
|||
private readonly IHubContext<NotificationHub, INotificationHub> _hubContext; |
|||
private readonly ILogger<NotificationAppService> _logger; |
|||
private readonly IJsonSerializer _jsonSerializer; |
|||
public NotificationHubAppService( |
|||
IHubContext<NotificationHub, INotificationHub> hubContext, |
|||
ILogger<NotificationAppService> logger, |
|||
IJsonSerializer jsonSerializer) |
|||
{ |
|||
_hubContext = hubContext; |
|||
_logger = logger; |
|||
_jsonSerializer = jsonSerializer; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送消息
|
|||
/// </summary>
|
|||
public virtual async Task SendMessageAsync(Guid id, string title, string content, MessageType messageType, MessageLevel messageLevel, string receiverUserId) |
|||
{ |
|||
switch (messageType) |
|||
{ |
|||
case MessageType.Common: |
|||
await SendMessageToClientByUserIdAsync(new SendNotificationDto(id, title, content, messageType, messageLevel), receiverUserId); |
|||
break; |
|||
case MessageType.BroadCast: |
|||
await SendMessageToAllClientAsync(new SendNotificationDto(id, title, content, messageType, messageLevel)); |
|||
break; |
|||
default: |
|||
throw new BusinessException(NotificationManagementErrorCodes.MessageTypeUnknown); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送消息指定客户端用户
|
|||
/// </summary>
|
|||
private async Task SendMessageToClientByUserIdAsync(SendNotificationDto sendNotificationDto, string receiverUserId) |
|||
{ |
|||
if (receiverUserId.IsNotNullOrWhiteSpace()) |
|||
{ |
|||
await _hubContext.Clients |
|||
.Users(new string[] { receiverUserId }) |
|||
.ReceiveTextMessageAsync(sendNotificationDto); |
|||
_logger.LogInformation($"通知模块收到消息:{_jsonSerializer.Serialize(sendNotificationDto)},发送给:{receiverUserId}"); |
|||
} |
|||
else |
|||
{ |
|||
_logger.LogWarning($"消息未指定发送人:{_jsonSerializer.Serialize(sendNotificationDto)}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送消息到所有客户端
|
|||
/// 广播消息
|
|||
/// </summary>
|
|||
private async Task SendMessageToAllClientAsync(SendNotificationDto sendNotificationDto) |
|||
{ |
|||
await _hubContext.Clients.All.ReceiveBroadCastMessageAsync(sendNotificationDto); |
|||
_logger.LogInformation($"通知模块收到消息:{_jsonSerializer.Serialize(sendNotificationDto)}"); |
|||
} |
|||
} |
|||
@ -1,29 +1,31 @@ |
|||
using Lion.AbpPro.SignalR.LocalEvent.Notification; |
|||
|
|||
namespace Lion.AbpPro.NotificationManagement.Notifications.LocalEventHandlers |
|||
{ |
|||
/// <summary>
|
|||
/// 创建消息事件处理
|
|||
/// </summary>
|
|||
public class NotificationCreatedLocalEventHandler : |
|||
ILocalEventHandler<CreatedNotificationLocalEvent>, |
|||
ITransientDependency |
|||
ILocalEventHandler<CreatedNotificationLocalEvent>, |
|||
ITransientDependency |
|||
{ |
|||
private readonly INotificationHubAppService _hubAppService; |
|||
private readonly INotificationManager _notificationManager; |
|||
|
|||
public NotificationCreatedLocalEventHandler(INotificationHubAppService hubAppService) |
|||
public NotificationCreatedLocalEventHandler( INotificationManager notificationManager) |
|||
{ |
|||
_hubAppService = hubAppService; |
|||
_notificationManager = notificationManager; |
|||
} |
|||
|
|||
public virtual Task HandleEventAsync(CreatedNotificationLocalEvent eventData) |
|||
public virtual async Task HandleEventAsync(CreatedNotificationLocalEvent eventData) |
|||
{ |
|||
return _hubAppService.SendMessageAsync( |
|||
eventData.NotificationEto.Id, |
|||
eventData.NotificationEto.Title, |
|||
eventData.NotificationEto.Content, |
|||
eventData.NotificationEto.MessageType, |
|||
eventData.NotificationEto.MessageLevel, |
|||
eventData.NotificationEto.ReceiveUserId.ToString()); |
|||
await _notificationManager.CreateAsync( |
|||
eventData.Id, |
|||
eventData.Title, |
|||
eventData.Content, |
|||
eventData.MessageType, |
|||
eventData.MessageLevel, |
|||
eventData.ReceiveUserId, |
|||
eventData.ReceiveUserName); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -1,72 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Lion.AbpPro.NotificationManagement.Notifications.Enums; |
|||
|
|||
|
|||
namespace Lion.AbpPro.NotificationManagement.Notifications.Etos |
|||
{ |
|||
public class NotificationEto |
|||
{ |
|||
public Guid Id { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 租户id
|
|||
/// </summary>
|
|||
public Guid? TenantId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息标题
|
|||
/// </summary>
|
|||
public string Title { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
public string Content { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息类型
|
|||
/// </summary>
|
|||
public MessageType MessageType { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息等级
|
|||
/// </summary>
|
|||
public MessageLevel MessageLevel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发送人
|
|||
/// </summary>
|
|||
public Guid SenderUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发送人用户名
|
|||
/// </summary>
|
|||
public string SenderUserName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 订阅人
|
|||
/// 消息类型是广播消息时,订阅人为空
|
|||
/// </summary>
|
|||
public Guid? ReceiveUserId { get; set; } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 接收人用户名
|
|||
/// 消息类型是广播消息时,订接收人用户名为空
|
|||
/// </summary>
|
|||
public string ReceiveUserName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 是否已读
|
|||
/// </summary>
|
|||
public bool Read { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 已读时间
|
|||
/// </summary>
|
|||
public DateTime? ReadTime { get; set; } |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
namespace Lion.AbpPro.NotificationManagement.Notifications.LocalEvents |
|||
{ |
|||
public class CreatedNotificationLocalEvent |
|||
{ |
|||
public NotificationEto NotificationEto { get; set; } |
|||
|
|||
private CreatedNotificationLocalEvent() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public CreatedNotificationLocalEvent(NotificationEto notificationEto) |
|||
{ |
|||
NotificationEto = notificationEto; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue