Изменение уведомлений

1. Изменил сущность уведомлений. Добавил дату регистрации уведомления.
2. Добавил миграцию.
3. Изменил репозитории. Убрал метод для обновления коллекции уведомлений.
4. Поправил запрос для отправки уведомлений и метод контроллера.
5. Поправил логику обновления уведомления. Теперь обновление состояния уведомления происходит в транспорте, после успешной отправки уведомления.
This commit is contained in:
parent 1639e9c153
commit 1b560dd0a2
15 changed files with 8501 additions and 143 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using AsbCloudApp.Data.User;
namespace AsbCloudApp.Data; namespace AsbCloudApp.Data;
@ -17,11 +18,6 @@ public class NotificationDto : IId
/// </summary> /// </summary>
public int IdUser { get; set; } public int IdUser { get; set; }
/// <summary>
/// Email получателя уведомления
/// </summary>
public string? UserEmail { get; set; }
/// <summary> /// <summary>
/// Id категории уведомления /// Id категории уведомления
/// </summary> /// </summary>
@ -37,6 +33,11 @@ public class NotificationDto : IId
/// </summary> /// </summary>
public string Message { get; set; } = null!; public string Message { get; set; } = null!;
/// <summary>
/// Дата регистрации уведомления
/// </summary>
public DateTime RegistrationDate { get; set; }
/// <summary> /// <summary>
/// Дата отправки уведомления /// Дата отправки уведомления
/// </summary> /// </summary>
@ -78,4 +79,9 @@ public class NotificationDto : IId
/// DTO категории уведомления /// DTO категории уведомления
/// </summary> /// </summary>
public NotificationCategoryDto NotificationCategory { get; set; } = null!; public NotificationCategoryDto NotificationCategory { get; set; } = null!;
/// <summary>
/// DTO получателя уведомления
/// </summary>
public UserDto User { get; set; } = null!;
} }

View File

@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
@ -12,15 +11,6 @@ namespace AsbCloudApp.Repositories;
/// </summary> /// </summary>
public interface INotificationRepository : ICrudRepository<NotificationDto> public interface INotificationRepository : ICrudRepository<NotificationDto>
{ {
/// <summary>
/// Обновление изменённых уведомлений
/// </summary>
/// <param name="notifications"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications,
CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Получение уведомлений по параметрам /// Получение уведомлений по параметрам
/// </summary> /// </summary>

View File

@ -1,3 +1,5 @@
using System.ComponentModel.DataAnnotations;
namespace AsbCloudApp.Requests; namespace AsbCloudApp.Requests;
/// <summary> /// <summary>
@ -6,32 +8,34 @@ namespace AsbCloudApp.Requests;
public class NotifyRequest public class NotifyRequest
{ {
/// <summary> /// <summary>
/// Id пользователя /// Id получателя уведомления
/// </summary> /// </summary>
[Required]
public int IdUser { get; set; } public int IdUser { get; set; }
/// <summary>
/// Email пользователя
/// </summary>
public string? UserEmail { get; set; }
/// <summary> /// <summary>
/// Id категории уведомления. Допустимое значение параметра: 1 /// Id категории уведомления. Допустимое значение параметра: 1
/// </summary> /// </summary>
[Required]
[Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
public int IdNotificationCategory { get; set; } public int IdNotificationCategory { get; set; }
/// <summary> /// <summary>
/// Заголовок уведомления /// Заголовок уведомления
/// </summary> /// </summary>
[Required]
public string Title { get; set; } = null!; public string Title { get; set; } = null!;
/// <summary> /// <summary>
/// Сообщение уведомления /// Сообщение уведомления
/// </summary> /// </summary>
[Required]
public string Message { get; set; } = null!; public string Message { get; set; } = null!;
/// <summary> /// <summary>
/// Id типа доставки уведомления. Допустимое значение: 0, 1 /// Id типа доставки уведомления. Допустимое значение: 0, 1
/// </summary> /// </summary>
[Required]
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
public int IdTransportType { get; set; } public int IdTransportType { get; set; }
} }

View File

@ -16,6 +16,7 @@ namespace AsbCloudApp.Services.Notifications;
public class NotificationService public class NotificationService
{ {
private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepository; private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepository;
private readonly IUserRepository userRepository;
private readonly INotificationRepository notificationRepository; private readonly INotificationRepository notificationRepository;
private readonly IEnumerable<INotificationTransportService> notificationTransportServices; private readonly IEnumerable<INotificationTransportService> notificationTransportServices;
@ -23,12 +24,15 @@ public class NotificationService
/// Сервис для работы с уведомлениями /// Сервис для работы с уведомлениями
/// </summary> /// </summary>
/// <param name="notificationCategoryRepository"></param> /// <param name="notificationCategoryRepository"></param>
/// <param name="userRepository"></param>
/// <param name="notificationRepository"></param> /// <param name="notificationRepository"></param>
/// <param name="notificationTransportServices"></param> /// <param name="notificationTransportServices"></param>
public NotificationService(ICrudRepository<NotificationCategoryDto> notificationCategoryRepository, public NotificationService(ICrudRepository<NotificationCategoryDto> notificationCategoryRepository,
IUserRepository userRepository,
INotificationRepository notificationRepository, INotificationRepository notificationRepository,
IEnumerable<INotificationTransportService> notificationTransportServices) IEnumerable<INotificationTransportService> notificationTransportServices)
{ {
this.userRepository = userRepository;
this.notificationCategoryRepository = notificationCategoryRepository; this.notificationCategoryRepository = notificationCategoryRepository;
this.notificationRepository = notificationRepository; this.notificationRepository = notificationRepository;
this.notificationTransportServices = notificationTransportServices; this.notificationTransportServices = notificationTransportServices;
@ -46,27 +50,26 @@ public class NotificationService
.GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken) .GetOrDefaultAsync(request.IdNotificationCategory, cancellationToken)
?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory)); ?? throw new ArgumentInvalidException("Категория уведомления не найдена", nameof(request.IdNotificationCategory));
var user = await userRepository.GetOrDefaultAsync(request.IdUser, cancellationToken)
?? throw new ArgumentInvalidException("Пользователь не найден" , nameof(request.IdUser));
var notification = new NotificationDto var notification = new NotificationDto
{ {
IdUser = request.IdUser, IdUser = request.IdUser,
UserEmail = request.UserEmail, RegistrationDate = DateTime.UtcNow,
IdNotificationCategory = request.IdNotificationCategory, IdNotificationCategory = request.IdNotificationCategory,
Title = request.Title, Title = request.Title,
Message = request.Message, Message = request.Message,
IdTransportType = request.IdTransportType IdTransportType = request.IdTransportType,
}; };
notification.Id = await notificationRepository.InsertAsync(notification, notification.Id = await notificationRepository.InsertAsync(notification, cancellationToken);
cancellationToken);
notification.NotificationCategory = notificationCategory; notification.NotificationCategory = notificationCategory;
notification.User = user;
var notificationTransportService = GetNotificationTransportService(request.IdTransportType); var notificationTransportService = GetNotificationTransportService(request.IdTransportType);
await notificationTransportService.SendAsync(notification, cancellationToken); await notificationTransportService.SendAsync(notification, cancellationToken);
await notificationRepository.UpdateAsync(notification,
cancellationToken);
} }
/// <summary> /// <summary>
@ -119,9 +122,6 @@ public class NotificationService
await notificationTransportService.SendRangeAsync(result.Items, await notificationTransportService.SendRangeAsync(result.Items,
cancellationToken); cancellationToken);
await notificationRepository.UpdateRangeAsync(result.Items,
cancellationToken);
} }
private INotificationTransportService GetNotificationTransportService(int idTransportType) private INotificationTransportService GetNotificationTransportService(int idTransportType)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_Registration_Date_Notification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "registration_date",
table: "t_notification",
type: "timestamp with time zone",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
comment: "Дата регистрации уведомления");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "registration_date",
table: "t_notification");
}
}
}

View File

@ -1194,6 +1194,11 @@ namespace AsbCloudDb.Migrations
.HasColumnName("read_date") .HasColumnName("read_date")
.HasComment("Дата прочтения уведомления"); .HasComment("Дата прочтения уведомления");
b.Property<DateTime>("RegistrationDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("registration_date")
.HasComment("Дата регистрации уведомления");
b.Property<DateTime?>("SentDate") b.Property<DateTime?>("SentDate")
.HasColumnType("timestamp with time zone") .HasColumnType("timestamp with time zone")
.HasColumnName("sent_date") .HasColumnName("sent_date")

View File

@ -24,6 +24,9 @@ public class Notification : IId
[Column("message"), Comment("Сообщение уведомления")] [Column("message"), Comment("Сообщение уведомления")]
public string Message { get; set; } = null!; public string Message { get; set; } = null!;
[Column("registration_date"), Comment("Дата регистрации уведомления")]
public DateTime RegistrationDate { get; set; }
[Column("sent_date"), Comment("Дата отправки уведомления")] [Column("sent_date"), Comment("Дата отправки уведомления")]
public DateTime? SentDate { get; set; } public DateTime? SentDate { get; set; }

View File

@ -1,13 +1,9 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
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;
@ -20,6 +16,7 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
{ {
private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet) private static IQueryable<Notification> MakeQueryNotification(DbSet<Notification> dbSet)
=> dbSet.Include(n => n.NotificationCategory) => dbSet.Include(n => n.NotificationCategory)
.Include(n => n.User)
.AsNoTracking(); .AsNoTracking();
public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache) public NotificationRepository(IAsbCloudDbContext dbContext, IMemoryCache memoryCache)
@ -27,31 +24,6 @@ public class NotificationRepository : CrudCacheRepositoryBase<NotificationDto, N
{ {
} }
public async Task<int> UpdateRangeAsync(IEnumerable<NotificationDto> notifications, CancellationToken cancellationToken)
{
if (!notifications.Any())
return 0;
var ids = notifications.Select(d => d.Id).ToArray();
var existingEntities = await dbSet
.Where(d => ids.Contains(d.Id))
.AsNoTracking()
.Select(d => d.Id)
.ToArrayAsync(cancellationToken);
if (ids.Length > existingEntities.Length)
return ICrudRepository<SetpointsRequestDto>.ErrorIdNotFound;
var entities = notifications.Select(Convert);
dbContext.Notifications.UpdateRange(entities);
var result = await dbContext.SaveChangesAsync(cancellationToken);
DropCache();
return result;
}
public async Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser, public async Task<PaginationContainer<NotificationDto>> GetNotificationsAsync(int idUser,
NotificationRequest request, NotificationRequest request,
CancellationToken cancellationToken) CancellationToken cancellationToken)

View File

@ -387,7 +387,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
await notificationService.NotifyAsync(new NotifyRequest await notificationService.NotifyAsync(new NotifyRequest
{ {
IdUser = user.Id, IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory, IdNotificationCategory = idNotificationCategory,
Title = subject, Title = subject,
Message = body, Message = body,
@ -410,7 +409,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
await notificationService.NotifyAsync(new NotifyRequest await notificationService.NotifyAsync(new NotifyRequest
{ {
IdUser = user.Id, IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory, IdNotificationCategory = idNotificationCategory,
Title = subject, Title = subject,
Message = body, Message = body,
@ -436,7 +434,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
await notificationService.NotifyAsync(new NotifyRequest await notificationService.NotifyAsync(new NotifyRequest
{ {
IdUser = user.Id, IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory, IdNotificationCategory = idNotificationCategory,
Title = subject, Title = subject,
Message = body, Message = body,
@ -458,7 +455,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
await notificationService.NotifyAsync(new NotifyRequest await notificationService.NotifyAsync(new NotifyRequest
{ {
IdUser = user.Id, IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory, IdNotificationCategory = idNotificationCategory,
Title = subject, Title = subject,
Message = body, Message = body,

View File

@ -7,9 +7,11 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services.Notifications; using AsbCloudApp.Services.Notifications;
using AsbCloudInfrastructure.Background; using AsbCloudInfrastructure.Background;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AsbCloudInfrastructure.Services.Email namespace AsbCloudInfrastructure.Services.Email
{ {
@ -48,16 +50,11 @@ namespace AsbCloudInfrastructure.Services.Email
return Task.CompletedTask; return Task.CompletedTask;
} }
if (string.IsNullOrWhiteSpace(notification.UserEmail)) var workId = MakeWorkId(notification.User.Email, notification.Title, notification.Message);
{
Trace.TraceWarning("User email is not null");
return Task.CompletedTask;
}
var workId = MakeWorkId(new []{ notification.UserEmail }, notification.Title, notification.Message);
if (!backgroundWorker.Contains(workId)) if (!backgroundWorker.Contains(workId))
{ {
var workAction = MakeEmailSendWorkAction(new []{ notification.UserEmail }, notification.Title, notification.Message); var workAction = MakeEmailSendWorkAction(notification);
var work = new WorkBase(workId, workAction); var work = new WorkBase(workId, workAction);
backgroundWorker.Push(work); backgroundWorker.Push(work);
} }
@ -74,24 +71,18 @@ namespace AsbCloudInfrastructure.Services.Email
} }
private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(IEnumerable<string> addresses, string subject, string htmlBody) private Func<string, IServiceProvider, CancellationToken, Task> MakeEmailSendWorkAction(NotificationDto notification)
{ {
var mailAddresses = new List<MailAddress>(); if(!MailAddress.TryCreate(notification.User.Email, out var mailAddress))
foreach (var address in addresses) Trace.TraceWarning($"Mail {notification.User.Email} is not correct.");
{
if (MailAddress.TryCreate(address, out MailAddress? mailAddress))
mailAddresses.Add(mailAddress);
else
Trace.TraceWarning($"Mail {address} is not correct.");
}
if (!mailAddresses.Any()) if (mailAddress is null)
throw new ArgumentException($"No valid email found. List:[{string.Join(',', addresses)}]", nameof(addresses)); throw new ArgumentInvalidException($"Mail {notification.User.Email} is not null.", nameof(notification.User.Email));
if (string.IsNullOrEmpty(subject)) if (string.IsNullOrWhiteSpace(notification.Title))
throw new ArgumentInvalidException($"{nameof(subject)} should be set", nameof(subject)); throw new ArgumentInvalidException($"{nameof(notification.Title)} should be set", nameof(notification.Title));
var workAction = async (string id, IServiceProvider serviceProvider, CancellationToken token) => return async (_, serviceProvider, token) =>
{ {
var from = new MailAddress(sender); var from = new MailAddress(sender);
var message = new MailMessage var message = new MailMessage
@ -99,12 +90,10 @@ namespace AsbCloudInfrastructure.Services.Email
From = from From = from
}; };
foreach (var mailAddress in mailAddresses) message.To.Add(mailAddress.Address);
message.To.Add(mailAddress);
message.BodyEncoding = System.Text.Encoding.UTF8; message.BodyEncoding = System.Text.Encoding.UTF8;
message.Body = htmlBody; message.Body = notification.Message;
message.Subject = subject; message.Subject = notification.Title;
message.IsBodyHtml = true; message.IsBodyHtml = true;
using var client = new SmtpClient(smtpServer); using var client = new SmtpClient(smtpServer);
@ -113,28 +102,23 @@ namespace AsbCloudInfrastructure.Services.Email
client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword); client.Credentials = new System.Net.NetworkCredential(sender, smtpPassword);
await client.SendMailAsync(message, token); await client.SendMailAsync(message, token);
Trace.TraceInformation($"Send email to {string.Join(',', addresses)} subj:{subject} html body count {htmlBody.Length}");
notification.SentDate = DateTime.UtcNow;
var notificationRepository = serviceProvider.GetService<INotificationRepository>();
await notificationRepository!.UpdateAsync(notification, token);
Trace.TraceInformation($"Send email to {notification.User.Email} subj:{notification.Title} html body count {notification.Message.Length}");
}; };
return workAction;
} }
private static string MakeWorkId(IEnumerable<string> addresses, string subject, string content) private static string MakeWorkId(string address, string subject, string content)
{ {
var hash = GetHashCode(addresses); var hash = address.GetHashCode();
hash ^= subject.GetHashCode(); hash ^= subject.GetHashCode();
hash ^= content.GetHashCode(); hash ^= content.GetHashCode();
return hash.ToString("x"); return hash.ToString("x");
} }
private static int GetHashCode(IEnumerable<string> strings)
{
int hash = -1397075115;
var enumerator = strings.GetEnumerator();
while (enumerator.MoveNext())
hash ^= enumerator.Current.GetHashCode();
return hash;
}
} }
} }

View File

@ -154,7 +154,6 @@ namespace AsbCloudInfrastructure.Services
await notificationService.NotifyAsync(new NotifyRequest await notificationService.NotifyAsync(new NotifyRequest
{ {
IdUser = user.Id, IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory, IdNotificationCategory = idNotificationCategory,
Title = subject, Title = subject,
Message = body, Message = body,

View File

@ -145,6 +145,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
.Returns(1); .Returns(1);
notificationService = new NotificationService(notificationCategoryRepositoryMock.Object, notificationService = new NotificationService(notificationCategoryRepositoryMock.Object,
userRepositoryMock.Object,
new Mock<INotificationRepository>().Object, new Mock<INotificationRepository>().Object,
new [] { notificationTransportServiceMock.Object }); new [] { notificationTransportServiceMock.Object });

View File

@ -19,15 +19,12 @@ namespace AsbCloudWebApi.Controllers;
[Route("api/notification")] [Route("api/notification")]
public class NotificationController : ControllerBase public class NotificationController : ControllerBase
{ {
private readonly IUserRepository userRepository;
private readonly NotificationService notificationService; private readonly NotificationService notificationService;
private readonly INotificationRepository notificationRepository; private readonly INotificationRepository notificationRepository;
public NotificationController(IUserRepository userRepository, public NotificationController(NotificationService notificationService,
NotificationService notificationService,
INotificationRepository notificationRepository) INotificationRepository notificationRepository)
{ {
this.userRepository = userRepository;
this.notificationService = notificationService; this.notificationService = notificationService;
this.notificationRepository = notificationRepository; this.notificationRepository = notificationRepository;
} }
@ -35,37 +32,14 @@ public class NotificationController : ControllerBase
/// <summary> /// <summary>
/// Отправка уведомления /// Отправка уведомления
/// </summary> /// </summary>
/// <param name="idUser">Id пользователя</param> /// <param name="request">Параметры запроса</param>
/// <param name="idNotificationCategory">Id категории уведомления. Допустимые: 1</param>
/// <param name="title">Заголовок уведомления</param>
/// <param name="message">Сообщение уведомления</param>
/// <param name="idTransportType">Id типа доставки уведомления. Допустимые: 0, 1</param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
[Route("send")] [Route("send")]
public async Task<IActionResult> SendAsync([Required] int idUser, public async Task<IActionResult> SendAsync(NotifyRequest request, CancellationToken cancellationToken)
[Required] [Range(minimum: 1, maximum: 1, ErrorMessage = "Id категории уведомления недоступно. Допустимые: 1")]
int idNotificationCategory,
[Required] string title,
[Required] string message,
[Required]
[Range(minimum: 0, maximum: 1, ErrorMessage = "Id способа отправки уведомления недоступно. Допустимые: 0, 1")]
int idTransportType,
CancellationToken cancellationToken)
{ {
var user = await userRepository.GetOrDefaultAsync(idUser, cancellationToken) await notificationService.NotifyAsync(request, cancellationToken);
?? throw new ArgumentInvalidException("Пользователь не найден", nameof(idUser));
await notificationService.NotifyAsync(new NotifyRequest
{
IdUser = user.Id,
UserEmail = user.Email,
IdNotificationCategory = idNotificationCategory,
Title = title,
Message = message,
IdTransportType = idTransportType
}, cancellationToken);
return Ok(); return Ok();
} }

View File

@ -4,6 +4,7 @@ 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 Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
@ -13,12 +14,16 @@ public class SignalRNotificationTransportService : INotificationTransportService
{ {
private readonly ConnectionManagerService connectionManagerService; private readonly ConnectionManagerService connectionManagerService;
private readonly IHubContext<NotificationHub> notificationHubContext; private readonly IHubContext<NotificationHub> notificationHubContext;
private readonly INotificationRepository notificationRepository;
private readonly SemaphoreSlim semaphoreSlim = new (1, 1);
public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService, public SignalRNotificationTransportService(ConnectionManagerService connectionManagerService,
IHubContext<NotificationHub> notificationHubContext) IHubContext<NotificationHub> notificationHubContext,
INotificationRepository notificationRepository)
{ {
this.connectionManagerService = connectionManagerService; this.connectionManagerService = connectionManagerService;
this.notificationHubContext = notificationHubContext; this.notificationHubContext = notificationHubContext;
this.notificationRepository = notificationRepository;
} }
public int IdTransportType => 0; public int IdTransportType => 0;
@ -38,6 +43,12 @@ public class SignalRNotificationTransportService : INotificationTransportService
.SendAsync(method, .SendAsync(method,
notification, notification,
cancellationToken); cancellationToken);
await semaphoreSlim.WaitAsync(cancellationToken);
await notificationRepository.UpdateAsync(notification, cancellationToken);
semaphoreSlim.Release();
} }
} }