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; |
using System.ComponentModel; |
||||
|
|
||||
namespace Lion.AbpPro.NotificationManagement.Notifications.Enums; |
namespace Lion.AbpPro.SignalR.Enums; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// 消息等级
|
/// 消息等级
|
||||
@ -1,6 +1,6 @@ |
|||||
using System.ComponentModel; |
using System.ComponentModel; |
||||
|
|
||||
namespace Lion.AbpPro.NotificationManagement.Notifications.Enums |
namespace Lion.AbpPro.SignalR.Enums |
||||
{ |
{ |
||||
/// <summary>
|
/// <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")] |
[HubRoute("SignalR/Notification")] |
||||
[Authorize] |
[Authorize] |
||||
[DisableAuditing] |
[DisableAuditing] |
||||
public class NotificationHub : AbpHub<INotificationHub> |
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 |
namespace Lion.AbpPro.NotificationManagement.Notifications.LocalEventHandlers |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// 创建消息事件处理
|
/// 创建消息事件处理
|
||||
/// </summary>
|
/// </summary>
|
||||
public class NotificationCreatedLocalEventHandler : |
public class NotificationCreatedLocalEventHandler : |
||||
ILocalEventHandler<CreatedNotificationLocalEvent>, |
ILocalEventHandler<CreatedNotificationLocalEvent>, |
||||
ITransientDependency |
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( |
await _notificationManager.CreateAsync( |
||||
eventData.NotificationEto.Id, |
eventData.Id, |
||||
eventData.NotificationEto.Title, |
eventData.Title, |
||||
eventData.NotificationEto.Content, |
eventData.Content, |
||||
eventData.NotificationEto.MessageType, |
eventData.MessageType, |
||||
eventData.NotificationEto.MessageLevel, |
eventData.MessageLevel, |
||||
eventData.NotificationEto.ReceiveUserId.ToString()); |
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