forked from ddrilling/AsbCloudServer
Изменил отправку уведомлений через SignalR
1. Добавил отправку всех неотправленных уведомлений и кол-во непрочитаннах уведомлений при первом подключении 2. При изменении статуса прочтения уведомления, клиенту отправляется информация о том сколько непрочитанных уведомлений ещё есть. 3. Добавил объект NotificationMessage, который отправляется клиенту. 4. Сделал небольшой рефакторинг
This commit is contained in:
parent
60921a2bcf
commit
5f459b79b8
@ -18,4 +18,8 @@
|
|||||||
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
|
<EditorConfigFiles Remove="D:\Source\AsbCloudApp\Services\.editorconfig" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AsbCloudDb\AsbCloudDb.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
@ -22,6 +23,25 @@ public interface INotificationRepository : ICrudRepository<NotificationDto>
|
|||||||
NotificationRequest request,
|
NotificationRequest request,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение всех уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="isSent"></param>
|
||||||
|
/// <param name="idTransportType"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<NotificationDto>> GetAllAsync(int? idUser, bool? isSent, int? idTransportType,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление уведомлений
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notifications"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Удаление уведомлений по параметрам
|
/// Удаление уведомлений по параметрам
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -16,7 +16,7 @@ public interface INotificationTransportService
|
|||||||
int IdTransportType { get; }
|
int IdTransportType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Отправка одного уведомлений
|
/// Отправка одного уведомления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notification"></param>
|
/// <param name="notification"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
|
@ -7,6 +7,7 @@ using AsbCloudApp.Data;
|
|||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
|
||||||
namespace AsbCloudApp.Services.Notifications;
|
namespace AsbCloudApp.Services.Notifications;
|
||||||
|
|
||||||
@ -42,8 +43,7 @@ public class NotificationService
|
|||||||
public async Task NotifyAsync(NotifyRequest request,
|
public async Task NotifyAsync(NotifyRequest request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var notificationCategory = await notificationCategoryRepository
|
var notificationCategory = await notificationCategoryRepository.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
||||||
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
|
|
||||||
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
|
||||||
|
|
||||||
var notification = new NotificationDto
|
var notification = new NotificationDto
|
||||||
@ -59,7 +59,7 @@ public class NotificationService
|
|||||||
notification.Id = await notificationRepository.InsertAsync(notification, cancellationToken);
|
notification.Id = await notificationRepository.InsertAsync(notification, cancellationToken);
|
||||||
notification.NotificationCategory = notificationCategory;
|
notification.NotificationCategory = notificationCategory;
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
|
var notificationTransportService = GetTransportService(request.IdTransportType);
|
||||||
|
|
||||||
await notificationTransportService.SendAsync(notification, cancellationToken);
|
await notificationTransportService.SendAsync(notification, cancellationToken);
|
||||||
}
|
}
|
||||||
@ -71,12 +71,11 @@ public class NotificationService
|
|||||||
/// <param name="isRead"></param>
|
/// <param name="isRead"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task UpdateNotificationAsync(int idNotification,
|
public async Task UpdateAsync(int idNotification,
|
||||||
bool isRead,
|
bool isRead,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var notification = await notificationRepository.GetOrDefaultAsync(idNotification,
|
var notification = await notificationRepository.GetOrDefaultAsync(idNotification, cancellationToken)
|
||||||
cancellationToken)
|
|
||||||
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
?? throw new ArgumentInvalidException("Уведомление не найдено", nameof(idNotification));
|
||||||
|
|
||||||
if(isRead && !notification.SentDate.HasValue)
|
if(isRead && !notification.SentDate.HasValue)
|
||||||
@ -95,25 +94,19 @@ public class NotificationService
|
|||||||
/// <param name="request"></param>
|
/// <param name="request"></param>
|
||||||
/// <param name="cancellationToken"></param>
|
/// <param name="cancellationToken"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task ResendNotificationAsync(int idUser,
|
public async Task RenotifyAsync(int idUser, CancellationToken cancellationToken)
|
||||||
NotificationRequest request,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (!request.IdTransportType.HasValue)
|
var notifications = await notificationRepository.GetAllAsync(idUser, false,
|
||||||
throw new ArgumentInvalidException("Id типа доставки уведомления должен иметь значение",
|
Notification.IdTransportTypeSignalR,
|
||||||
nameof(request.IdTransportType));
|
|
||||||
|
|
||||||
var result = await notificationRepository.GetNotificationsAsync(idUser,
|
|
||||||
request,
|
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
var notificationTransportService = GetNotificationTransportService(request.IdTransportType.Value);
|
var notificationTransportService = GetTransportService(Notification.IdTransportTypeSignalR);
|
||||||
|
|
||||||
await notificationTransportService.SendRangeAsync(result.Items,
|
await notificationTransportService.SendRangeAsync(notifications,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private INotificationTransportService GetNotificationTransportService(int idTransportType)
|
private INotificationTransportService GetTransportService(int idTransportType)
|
||||||
{
|
{
|
||||||
var notificationTransportService = notificationTransportServices
|
var notificationTransportService = notificationTransportServices
|
||||||
.FirstOrDefault(s => s.IdTransportType == idTransportType)
|
.FirstOrDefault(s => s.IdTransportType == idTransportType)
|
||||||
|
@ -8,6 +8,9 @@ namespace AsbCloudDb.Model;
|
|||||||
[Table("t_notification"), Comment("Уведомления")]
|
[Table("t_notification"), Comment("Уведомления")]
|
||||||
public class Notification : IId
|
public class Notification : IId
|
||||||
{
|
{
|
||||||
|
public const int IdTransportTypeSignalR = 0;
|
||||||
|
public const int IdTransportTypeTypeEmail = 1;
|
||||||
|
|
||||||
[Key]
|
[Key]
|
||||||
[Column("id")]
|
[Column("id")]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb;
|
using AsbCloudDb;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
@ -54,10 +57,55 @@ public class NotificationRepository : CrudRepositoryBase<NotificationDto, Notifi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> DeleteAsync(NotificationDeleteRequest request, CancellationToken cancellationToken)
|
public async Task<IEnumerable<NotificationDto>> GetAllAsync(int? idUser, bool? isSent, int? idTransportType,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var query = dbContext.Notifications.AsQueryable();
|
var query = dbContext.Notifications.AsQueryable();
|
||||||
|
|
||||||
|
if (idUser.HasValue)
|
||||||
|
query = query.Where(n => n.IdUser == idUser);
|
||||||
|
|
||||||
|
if(isSent.HasValue)
|
||||||
|
query = isSent.Value ?
|
||||||
|
query.Where(n => n.SentDate != null)
|
||||||
|
: query.Where(n => n.SentDate == null);
|
||||||
|
|
||||||
|
if (idTransportType.HasValue)
|
||||||
|
query = query.Where(n => n.IdTransportType == idTransportType);
|
||||||
|
|
||||||
|
return await query.AsNoTracking().Select(n => n.Adapt<NotificationDto>())
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!notifications.Any())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var ids = notifications.Select(d => d.Id);
|
||||||
|
|
||||||
|
var existingEntities = await dbSet
|
||||||
|
.Where(d => ids.Contains(d.Id))
|
||||||
|
.AsNoTracking()
|
||||||
|
.Select(d => d.Id)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (ids.Count() > existingEntities.Length)
|
||||||
|
return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;
|
||||||
|
|
||||||
|
var entities = notifications.Select(Convert);
|
||||||
|
|
||||||
|
dbContext.Notifications.UpdateRange(entities);
|
||||||
|
|
||||||
|
return await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> DeleteAsync(NotificationDeleteRequest request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var query = dbContext.Notifications
|
||||||
|
.Include(n => n.NotificationCategory)
|
||||||
|
.AsQueryable();
|
||||||
|
|
||||||
if (request.IdCategory.HasValue)
|
if (request.IdCategory.HasValue)
|
||||||
query = query.Where(n => n.IdNotificationCategory == request.IdCategory.Value);
|
query = query.Where(n => n.IdNotificationCategory == request.IdCategory.Value);
|
||||||
|
|
||||||
@ -72,16 +120,15 @@ public class NotificationRepository : CrudRepositoryBase<NotificationDto, Notifi
|
|||||||
return dbContext.SaveChangesAsync(cancellationToken);
|
return dbContext.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetUnreadCountAsync(int idUser, int idTransportType, CancellationToken cancellationToken)
|
public Task<int> GetUnreadCountAsync(int idUser, int idTransportType, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var count = await dbContext.Notifications
|
return dbContext.Notifications
|
||||||
.Where(n => n.ReadDate == null)
|
.Where(n => !n.ReadDate.HasValue &&
|
||||||
.Where(n => n.IdUser == idUser)
|
n.SentDate.HasValue &&
|
||||||
.Where(n => n.IdTransportType == idTransportType)
|
n.IdUser == idUser &&
|
||||||
.CountAsync(cancellationToken);
|
n.IdTransportType == idTransportType)
|
||||||
|
.CountAsync(cancellationToken);
|
||||||
return count;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private IQueryable<Notification> BuildQuery(int idUser,
|
private IQueryable<Notification> BuildQuery(int idUser,
|
||||||
NotificationRequest request)
|
NotificationRequest request)
|
||||||
|
@ -9,6 +9,7 @@ using AsbCloudApp.Data;
|
|||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -40,7 +41,7 @@ namespace AsbCloudInfrastructure.Services.Email
|
|||||||
this.backgroundWorker = backgroundWorker;
|
this.backgroundWorker = backgroundWorker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IdTransportType => 1;
|
public int IdTransportType => Notification.IdTransportTypeTypeEmail;
|
||||||
|
|
||||||
public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken)
|
public Task SendAsync(NotificationDto notification, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ using AsbCloudApp.Exceptions;
|
|||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
@ -21,12 +22,15 @@ public class NotificationController : ControllerBase
|
|||||||
{
|
{
|
||||||
private readonly NotificationService notificationService;
|
private readonly NotificationService notificationService;
|
||||||
private readonly INotificationRepository notificationRepository;
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
private readonly NotificationPublisher notificationPublisher;
|
||||||
|
|
||||||
public NotificationController(NotificationService notificationService,
|
public NotificationController(NotificationService notificationService,
|
||||||
INotificationRepository notificationRepository)
|
INotificationRepository notificationRepository,
|
||||||
|
NotificationPublisher notificationPublisher)
|
||||||
{
|
{
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
this.notificationRepository = notificationRepository;
|
this.notificationRepository = notificationRepository;
|
||||||
|
this.notificationPublisher = notificationPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -55,10 +59,17 @@ public class NotificationController : ControllerBase
|
|||||||
[Required] bool isRead,
|
[Required] bool isRead,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await notificationService.UpdateNotificationAsync(idNotification,
|
var idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
await notificationService.UpdateAsync(idNotification,
|
||||||
isRead,
|
isRead,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
|
await notificationPublisher.PublishCountUnreadAsync(idUser.Value, cancellationToken);
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,28 +136,7 @@ public class NotificationController : ControllerBase
|
|||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение количества непрочитанных уведомлений
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idTransportType"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet]
|
|
||||||
[Route("unreadNotificationCount")]
|
|
||||||
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
|
|
||||||
public async Task<IActionResult> GetUnreadCountAsync([FromQuery] int idTransportType, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
int? idUser = User.GetUserId();
|
|
||||||
|
|
||||||
if (!idUser.HasValue)
|
|
||||||
return Forbid();
|
|
||||||
|
|
||||||
var result = await notificationRepository.GetUnreadCountAsync(idUser.Value, idTransportType, cancellationToken);
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Удаление уведомлений
|
/// Удаление уведомлений
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request">Параметры запроса</param>
|
/// <param name="request">Параметры запроса</param>
|
||||||
|
@ -141,6 +141,8 @@ namespace AsbCloudWebApi
|
|||||||
{
|
{
|
||||||
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
|
services.AddTransient<INotificationTransportService, SignalRNotificationTransportService>();
|
||||||
services.AddTransient<INotificationTransportService, EmailNotificationTransportService>();
|
services.AddTransient<INotificationTransportService, EmailNotificationTransportService>();
|
||||||
|
|
||||||
|
services.AddTransient<NotificationPublisher>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
AsbCloudWebApi/SignalR/Messages/NotificationMessage.cs
Normal file
11
AsbCloudWebApi/SignalR/Messages/NotificationMessage.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Messages;
|
||||||
|
|
||||||
|
public class NotificationMessage
|
||||||
|
{
|
||||||
|
public IEnumerable<NotificationDto>? Notifications { get; set; }
|
||||||
|
|
||||||
|
public int CountUnread { get; set; }
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Requests;
|
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
using AsbCloudWebApi.SignalR.Services;
|
using AsbCloudWebApi.SignalR.Services;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@ -14,12 +13,15 @@ public class NotificationHub : BaseHub
|
|||||||
{
|
{
|
||||||
private readonly ConnectionManagerService connectionManagerService;
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
private readonly NotificationService notificationService;
|
private readonly NotificationService notificationService;
|
||||||
|
private readonly NotificationPublisher notificationPublisher;
|
||||||
|
|
||||||
public NotificationHub(ConnectionManagerService connectionManagerService,
|
public NotificationHub(ConnectionManagerService connectionManagerService,
|
||||||
NotificationService notificationService)
|
NotificationService notificationService,
|
||||||
|
NotificationPublisher notificationPublisher)
|
||||||
{
|
{
|
||||||
this.connectionManagerService = connectionManagerService;
|
this.connectionManagerService = connectionManagerService;
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
|
this.notificationPublisher = notificationPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
@ -35,9 +37,10 @@ public class NotificationHub : BaseHub
|
|||||||
|
|
||||||
await base.OnConnectedAsync();
|
await base.OnConnectedAsync();
|
||||||
|
|
||||||
await notificationService.ResendNotificationAsync(idUser.Value,
|
await notificationPublisher.PublishCountUnreadAsync(idUser.Value, CancellationToken.None);
|
||||||
new NotificationRequest { IsSent = false, IdTransportType = 0},
|
|
||||||
CancellationToken.None);
|
await notificationService.RenotifyAsync(idUser.Value,
|
||||||
|
CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Exception? exception)
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
||||||
|
76
AsbCloudWebApi/SignalR/Services/NotificationPublisher.cs
Normal file
76
AsbCloudWebApi/SignalR/Services/NotificationPublisher.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using AsbCloudWebApi.SignalR.Messages;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
|
|
||||||
|
public class NotificationPublisher
|
||||||
|
{
|
||||||
|
private readonly ConnectionManagerService connectionManagerService;
|
||||||
|
private readonly IHubContext<NotificationHub> notificationHubContext;
|
||||||
|
private readonly INotificationRepository notificationRepository;
|
||||||
|
|
||||||
|
public NotificationPublisher(ConnectionManagerService connectionManagerService,
|
||||||
|
IHubContext<NotificationHub> notificationHubContext,
|
||||||
|
INotificationRepository notificationRepository)
|
||||||
|
{
|
||||||
|
this.connectionManagerService = connectionManagerService;
|
||||||
|
this.notificationHubContext = notificationHubContext;
|
||||||
|
this.notificationRepository = notificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PublishAsync(IGrouping<int, NotificationDto> groupedNotifications, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var connectionId = connectionManagerService.GetConnectionIdByUserId(groupedNotifications.Key);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(connectionId))
|
||||||
|
{
|
||||||
|
foreach (var notification in groupedNotifications)
|
||||||
|
{
|
||||||
|
notification.SentDate = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notifications = groupedNotifications.Select(n => n);
|
||||||
|
|
||||||
|
await notificationRepository.UpdateRangeAsync(notifications,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
await PublishMessageAsync(connectionId, new NotificationMessage
|
||||||
|
{
|
||||||
|
Notifications = notifications,
|
||||||
|
CountUnread = await notificationRepository.GetUnreadCountAsync(groupedNotifications.Key,
|
||||||
|
Notification.IdTransportTypeSignalR,
|
||||||
|
cancellationToken)
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PublishCountUnreadAsync(int idUser, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var connectionId = connectionManagerService.GetConnectionIdByUserId(idUser);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(connectionId))
|
||||||
|
{
|
||||||
|
await PublishMessageAsync(connectionId, new NotificationMessage
|
||||||
|
{
|
||||||
|
CountUnread = await notificationRepository.GetUnreadCountAsync(idUser, 0,
|
||||||
|
cancellationToken)
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PublishMessageAsync(string connectionId, NotificationMessage message,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await notificationHubContext.Clients.Client(connectionId)
|
||||||
|
.SendAsync("receiveNotifications",
|
||||||
|
message,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
@ -4,10 +4,9 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AsbCloudApp.Data;
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Repositories;
|
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
using AsbCloudInfrastructure.Background;
|
using AsbCloudInfrastructure.Background;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.SignalR.Services;
|
namespace AsbCloudWebApi.SignalR.Services;
|
||||||
@ -15,66 +14,44 @@ namespace AsbCloudWebApi.SignalR.Services;
|
|||||||
public class SignalRNotificationTransportService : INotificationTransportService
|
public class SignalRNotificationTransportService : INotificationTransportService
|
||||||
{
|
{
|
||||||
private readonly NotificationBackgroundWorker backgroundWorker;
|
private readonly NotificationBackgroundWorker backgroundWorker;
|
||||||
private readonly ConnectionManagerService connectionManagerService;
|
|
||||||
private readonly IHubContext<NotificationHub> notificationHubContext;
|
|
||||||
|
|
||||||
public SignalRNotificationTransportService(NotificationBackgroundWorker backgroundWorker,
|
public SignalRNotificationTransportService(NotificationBackgroundWorker backgroundWorker)
|
||||||
ConnectionManagerService connectionManagerService,
|
|
||||||
IHubContext<NotificationHub> notificationHubContext)
|
|
||||||
{
|
{
|
||||||
this.backgroundWorker = backgroundWorker;
|
this.backgroundWorker = backgroundWorker;
|
||||||
this.connectionManagerService = connectionManagerService;
|
|
||||||
this.notificationHubContext = notificationHubContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IdTransportType => 0;
|
public int IdTransportType => Notification.IdTransportTypeSignalR;
|
||||||
|
|
||||||
public Task SendAsync(NotificationDto notification,
|
public Task SendAsync(NotificationDto notification,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken) => SendRangeAsync(new[] { notification }, cancellationToken);
|
||||||
{
|
|
||||||
var workId = notification.Id.ToString();
|
|
||||||
|
|
||||||
if (!backgroundWorker.Contains(workId))
|
|
||||||
{
|
|
||||||
var connectionId = connectionManagerService.GetConnectionIdByUserId(notification.IdUser);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(connectionId))
|
|
||||||
{
|
|
||||||
var workAction = MakeSignalRSendWorkAction(notification, connectionId);
|
|
||||||
var work = new WorkBase(workId, workAction);
|
|
||||||
backgroundWorker.Push(work);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task SendRangeAsync(IEnumerable<NotificationDto> notifications,
|
public Task SendRangeAsync(IEnumerable<NotificationDto> notifications,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tasks = notifications
|
var workId = HashCode.Combine(notifications.Select(n => n.Id)).ToString("x");
|
||||||
.Select(notification => SendAsync(notification, cancellationToken));
|
|
||||||
|
|
||||||
return Task.WhenAll(tasks);
|
if (backgroundWorker.Contains(workId))
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var workAction = MakeSignalRSendWorkAction(notifications);
|
||||||
|
var work = new WorkBase(workId, workAction);
|
||||||
|
backgroundWorker.Push(work);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<string, IServiceProvider, CancellationToken, Task> MakeSignalRSendWorkAction(NotificationDto notification,
|
private Func<string, IServiceProvider, CancellationToken, Task> MakeSignalRSendWorkAction(IEnumerable<NotificationDto> notifications)
|
||||||
string connectionId)
|
|
||||||
{
|
{
|
||||||
const string method = "receiveNotifications";
|
|
||||||
|
|
||||||
return async (_, serviceProvider, cancellationToken) =>
|
return async (_, serviceProvider, cancellationToken) =>
|
||||||
{
|
{
|
||||||
notification.SentDate = DateTime.UtcNow;
|
var notificationPublisher = serviceProvider.GetRequiredService<NotificationPublisher>();
|
||||||
|
|
||||||
await notificationHubContext.Clients.Client(connectionId)
|
|
||||||
.SendAsync(method,
|
|
||||||
notification,
|
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
var notificationRepository = serviceProvider.GetRequiredService<INotificationRepository>();
|
|
||||||
|
|
||||||
await notificationRepository.UpdateAsync(notification, cancellationToken);
|
var groupedNotificationsByUsers = notifications.GroupBy(n => n.IdUser);
|
||||||
|
|
||||||
|
foreach (var groupedNotificationByUser in groupedNotificationsByUsers)
|
||||||
|
{
|
||||||
|
await notificationPublisher.PublishAsync(groupedNotificationByUser, cancellationToken);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user