diff --git a/AsbCloudApp/Services/Notifications/INotificationSender.cs b/AsbCloudApp/Services/Notifications/INotificationSender.cs
new file mode 100644
index 00000000..faa64b9e
--- /dev/null
+++ b/AsbCloudApp/Services/Notifications/INotificationSender.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudApp.Data;
+
+namespace AsbCloudApp.Services.Notifications;
+
+///
+/// Интерфейс для отправителя уведомлений
+///
+public interface INotificationSender
+{
+ ///
+ /// Способ отправки уведомлений
+ ///
+ NotificationTransport NotificationTransport { get; }
+
+ ///
+ /// Отправка одного уведомлений
+ ///
+ ///
+ ///
+ ///
+ Task SendAsync(NotificationDto notification,
+ CancellationToken cancellationToken);
+
+ ///
+ /// Отправка нескольких уведомлений
+ ///
+ ///
+ ///
+ ///
+ Task SendRangeAsync(IEnumerable notifications,
+ CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/Notifications/INotificationSenderManager.cs b/AsbCloudApp/Services/Notifications/INotificationSenderManager.cs
new file mode 100644
index 00000000..228308cd
--- /dev/null
+++ b/AsbCloudApp/Services/Notifications/INotificationSenderManager.cs
@@ -0,0 +1,16 @@
+using AsbCloudApp.Data;
+
+namespace AsbCloudApp.Services.Notifications;
+
+///
+///
+///
+public interface INotificationSenderManager
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ INotificationSender? GetOrDefault(NotificationTransport notificationTransport);
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/INotificationService.cs b/AsbCloudApp/Services/Notifications/INotificationService.cs
similarity index 66%
rename from AsbCloudApp/Services/INotificationService.cs
rename to AsbCloudApp/Services/Notifications/INotificationService.cs
index 973e4c8d..746b33f9 100644
--- a/AsbCloudApp/Services/INotificationService.cs
+++ b/AsbCloudApp/Services/Notifications/INotificationService.cs
@@ -1,8 +1,9 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Data;
-namespace AsbCloudApp.Services;
+namespace AsbCloudApp.Services.Notifications;
///
/// Интерфейс для работы с уведомлениями
@@ -10,26 +11,26 @@ namespace AsbCloudApp.Services;
public interface INotificationService
{
///
- /// Метод отправки нового уведомления
+ /// Отправка нового уведомления
///
///
- ///
///
///
- ///
+ ///
///
+ ///
///
///
- Task SendNotificationAsync(int idUser,
- int idNotificationTransport,
+ Task NotifyAsync(int idUser,
int idNotificationCategory,
string title,
- string subject,
+ string message,
TimeSpan timeToLife,
+ NotificationTransport notificationTransport,
CancellationToken cancellationToken);
///
- /// Метод обновления уведомления
+ /// Обновление уведомления
///
///
///
@@ -40,13 +41,13 @@ public interface INotificationService
CancellationToken cancellationToken);
///
- /// Метод отправки уведомлений, которые не были отправлены
+ /// Отправка уведомлений, которые не были отправлены
///
///
- ///
+ ///
///
///
Task ResendNotificationAsync(int idUser,
- int idNotificationTransport,
+ NotificationTransport notificationTransport,
CancellationToken cancellationToken);
}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
index 01645d15..2d88349b 100644
--- a/AsbCloudInfrastructure/DependencyInjection.cs
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -23,6 +23,8 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
+using AsbCloudApp.Services.Notifications;
+using AsbCloudInfrastructure.Services.Notifications;
namespace AsbCloudInfrastructure
{
@@ -145,8 +147,7 @@ namespace AsbCloudInfrastructure
services.AddTransient();
services.AddTransient();
- services.AddSingleton();
-
+
// admin crud services:
services.AddTransient, CrudCacheRepositoryBase>(s =>
new CrudCacheRepositoryBase(
diff --git a/AsbCloudInfrastructure/Services/Notifications/NotificationSenderManager.cs b/AsbCloudInfrastructure/Services/Notifications/NotificationSenderManager.cs
new file mode 100644
index 00000000..cd71ec79
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Notifications/NotificationSenderManager.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using AsbCloudApp.Data;
+using AsbCloudApp.Services.Notifications;
+
+namespace AsbCloudInfrastructure.Services.Notifications;
+
+public class NotificationSenderManager : INotificationSenderManager
+{
+ private readonly IEnumerable notificationSenders;
+
+ public NotificationSenderManager(IEnumerable notificationSenders)
+ {
+ this.notificationSenders = notificationSenders;
+ }
+
+ public INotificationSender? GetOrDefault(NotificationTransport notificationTransport)
+ {
+ return notificationSenders.FirstOrDefault(x => x.NotificationTransport == notificationTransport);
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs b/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs
new file mode 100644
index 00000000..bfa055d6
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Notifications/NotificationService.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Exceptions;
+using AsbCloudApp.Repositories;
+using AsbCloudApp.Services.Notifications;
+
+namespace AsbCloudInfrastructure.Services.Notifications;
+
+public class NotificationService : INotificationService
+{
+ private readonly INotificationSenderManager notificationSenderManager;
+ private readonly INotificationRepository notificationRepository;
+
+ public NotificationService(INotificationSenderManager notificationSenderManager,
+ INotificationRepository notificationRepository)
+ {
+ this.notificationSenderManager = notificationSenderManager;
+ this.notificationRepository = notificationRepository;
+ }
+
+ public async Task NotifyAsync(int idUser,
+ int idNotificationCategory,
+ string title,
+ string message,
+ TimeSpan timeToLife,
+ NotificationTransport notificationTransport,
+ CancellationToken cancellationToken)
+ {
+ NotificationDto notification = new()
+ {
+ IdUser = idUser,
+ IdNotificationCategory = idNotificationCategory,
+ Title = title,
+ Message = message,
+ TimeToLife = timeToLife,
+ NotificationTransport = notificationTransport,
+ NotificationState = NotificationState.Registered
+ };
+
+ await notificationRepository.InsertAsync(notification,
+ cancellationToken);
+
+ var notificationSender = notificationSenderManager.GetOrDefault(notificationTransport);
+
+ if(notificationSender is null)
+ throw new ArgumentInvalidException("Метод отправки уведомления не найден", nameof(notificationTransport));
+
+ await notificationSender.SendAsync(notification, cancellationToken);
+ }
+
+ public async Task UpdateNotificationAsync(int idNotification,
+ bool isRead,
+ CancellationToken cancellationToken)
+ {
+ var notification = await notificationRepository.GetOrDefaultAsync(idNotification,
+ cancellationToken) ?? throw new ArgumentInvalidException("Уведомление не найдено",
+ nameof(idNotification));
+
+ notification.NotificationState = isRead ? NotificationState.Read : NotificationState.Sent;
+
+ await notificationRepository.UpdateAsync(notification,
+ cancellationToken);
+ }
+
+ public async Task ResendNotificationAsync(int idUser,
+ NotificationTransport notificationTransport,
+ CancellationToken cancellationToken)
+ {
+ var notifications = await notificationRepository.GetUnsentNotificationsAsync(idUser,
+ notificationTransport,
+ cancellationToken);
+
+ var notificationSender = notificationSenderManager.GetOrDefault(notificationTransport);
+
+ if(notificationSender is null)
+ throw new ArgumentInvalidException("Отправитель уведомления не найден", nameof(notificationTransport));
+
+ await notificationSender.SendRangeAsync(notifications, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/NotificationController.cs b/AsbCloudWebApi/Controllers/NotificationController.cs
index 07fe4ace..d9834779 100644
--- a/AsbCloudWebApi/Controllers/NotificationController.cs
+++ b/AsbCloudWebApi/Controllers/NotificationController.cs
@@ -4,7 +4,8 @@ using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
-using AsbCloudApp.Services;
+using AsbCloudApp.Requests;
+using AsbCloudApp.Services.Notifications;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -29,39 +30,39 @@ public class NotificationController : ControllerBase
}
///
- /// Метод отправки уведомления
+ /// Отправка уведомления
///
/// Id пользователя
- /// Id способа отправки уведомления
/// Id категории уведомления
/// Заголовок уведомления
- /// Сообщение уведомления
+ /// Сообщение уведомления
/// Время жизни уведомления
+ /// Способ отправки уведомления
///
///
[HttpPost]
[Route("send")]
public async Task SendAsync([Required] int idUser,
- [Required] int idNotificationTransport,
[Required] int idNotificationCategory,
[Required] string title,
- [Required] string subject,
+ [Required] string message,
[Required] TimeSpan timeToLife,
+ [Required] NotificationTransport notificationTransport,
CancellationToken cancellationToken)
{
- await notificationService.SendNotificationAsync(idUser,
- idNotificationTransport,
+ await notificationService.NotifyAsync(idUser,
idNotificationCategory,
title,
- subject,
+ message,
timeToLife,
+ notificationTransport,
cancellationToken);
return Ok();
}
///
- /// Метод обновления уведомления
+ /// Обновление уведомления
///
/// Id уведомления
/// Прочитано ли уведомление
@@ -79,21 +80,17 @@ public class NotificationController : ControllerBase
return Ok();
}
-
+
///
- /// Метод получения уведомлений по параметрам
+ /// Получение списка уведомлений
///
- /// Кол-во пропускаемых записей
- /// Кол-во выбираемых записей
- /// Id способа доставки уведомления
+ /// Параметры запроса
///
///
[HttpGet]
[Route("getList")]
[ProducesResponseType(typeof(PaginationContainer), (int)System.Net.HttpStatusCode.OK)]
- public async Task GetListAsync(int? skip,
- int? take,
- [Required] int idNotificationTransport,
+ public async Task GetListAsync([FromQuery] NotificationRequest request,
CancellationToken cancellationToken)
{
int? idUser = User.GetUserId();
@@ -101,17 +98,15 @@ public class NotificationController : ControllerBase
if (!idUser.HasValue)
return Forbid();
- var result = await notificationRepository.GetNotificationsAsync(skip,
- take,
- idUser.Value,
- idNotificationTransport,
+ var result = await notificationRepository.GetNotificationsAsync(idUser.Value,
+ request,
cancellationToken);
return Ok(result);
}
///
- /// Метод удаления уведомления
+ /// Удаление уведомления
///
/// Id уведомления
///
diff --git a/AsbCloudWebApi/DependencyInjection.cs b/AsbCloudWebApi/DependencyInjection.cs
index 6b1fc6b4..5d50561a 100644
--- a/AsbCloudWebApi/DependencyInjection.cs
+++ b/AsbCloudWebApi/DependencyInjection.cs
@@ -9,6 +9,9 @@ using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
+using AsbCloudApp.Services.Notifications;
+using AsbCloudInfrastructure.Services.Notifications;
+using AsbCloudWebApi.SignalR.Services;
using Microsoft.OpenApi.Any;
namespace AsbCloudWebApi
@@ -105,5 +108,11 @@ namespace AsbCloudWebApi
};
});
}
+
+ public static void AddNotificationSenders(this IServiceCollection services)
+ {
+ services.AddScoped();
+ services.AddTransient();
+ }
}
}
diff --git a/AsbCloudWebApi/SignalR/ConnectionManager/ConnectionManager.cs b/AsbCloudWebApi/SignalR/ConnectionManager/ConnectionManager.cs
index 656c28ff..23c187bd 100644
--- a/AsbCloudWebApi/SignalR/ConnectionManager/ConnectionManager.cs
+++ b/AsbCloudWebApi/SignalR/ConnectionManager/ConnectionManager.cs
@@ -4,22 +4,22 @@ namespace AsbCloudWebApi.SignalR.ConnectionManager;
public class ConnectionManager : IConnectionManager
{
- private readonly ConcurrentDictionary _connections = new();
+ private readonly ConcurrentDictionary _connections = new();
- public void AddConnection(string userId,
+ public void AddConnection(int userId,
string connectionId)
{
_connections.TryAdd(userId, connectionId);
}
- public void RemoveConnection(string userId)
+ public void RemoveConnection(int userId)
{
_connections.TryRemove(userId, out _);
}
- public string? GetConnectionIdByUserId(string userId)
+ public string? GetConnectionIdByUserId(int userId)
{
- _connections.TryGetValue(userId, out string? connectionId);
+ _connections.TryGetValue(userId, out var connectionId);
return connectionId;
}
}
\ No newline at end of file
diff --git a/AsbCloudWebApi/SignalR/ConnectionManager/IConnectionManager.cs b/AsbCloudWebApi/SignalR/ConnectionManager/IConnectionManager.cs
index 9584d32b..e8f34650 100644
--- a/AsbCloudWebApi/SignalR/ConnectionManager/IConnectionManager.cs
+++ b/AsbCloudWebApi/SignalR/ConnectionManager/IConnectionManager.cs
@@ -2,10 +2,10 @@ namespace AsbCloudWebApi.SignalR.ConnectionManager;
public interface IConnectionManager
{
- void AddConnection(string userId,
+ void AddConnection(int userId,
string connectionId);
- void RemoveConnection(string userId);
+ void RemoveConnection(int userId);
- string? GetConnectionIdByUserId(string userId);
+ string? GetConnectionIdByUserId(int userId);
}
\ No newline at end of file
diff --git a/AsbCloudWebApi/SignalR/NotificationHub.cs b/AsbCloudWebApi/SignalR/NotificationHub.cs
index 322808cc..99983f14 100644
--- a/AsbCloudWebApi/SignalR/NotificationHub.cs
+++ b/AsbCloudWebApi/SignalR/NotificationHub.cs
@@ -1,10 +1,9 @@
using System.Threading;
using System.Threading.Tasks;
-using AsbCloudApp.Services;
-using AsbCloudWebApi.Options.Notifications;
+using AsbCloudApp.Data;
+using AsbCloudApp.Services.Notifications;
using AsbCloudWebApi.SignalR.ConnectionManager;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.Extensions.Options;
namespace AsbCloudWebApi.SignalR;
@@ -13,25 +12,22 @@ public class NotificationHub : BaseHub
{
private readonly IConnectionManager connectionManager;
private readonly INotificationService notificationService;
- private readonly NotificationsOptionsSignalR notificationsOptionsSignalR;
public NotificationHub(IConnectionManager connectionManager,
- INotificationService notificationService,
- IOptions notificationsOptionsSignalR)
+ INotificationService notificationService)
{
this.connectionManager = connectionManager;
this.notificationService = notificationService;
- this.notificationsOptionsSignalR = notificationsOptionsSignalR.Value;
}
public async Task OnConnected(int idUser)
{
string connectionId = Context.ConnectionId;
- connectionManager.AddConnection(idUser.ToString(), connectionId);
+ connectionManager.AddConnection(idUser, connectionId);
await notificationService.ResendNotificationAsync(idUser,
- notificationsOptionsSignalR.IdTransport,
+ NotificationTransport.SignalR,
CancellationToken.None);
await base.OnConnectedAsync();
diff --git a/AsbCloudWebApi/SignalR/Services/SignalRNotificationSender.cs b/AsbCloudWebApi/SignalR/Services/SignalRNotificationSender.cs
new file mode 100644
index 00000000..bf7c226e
--- /dev/null
+++ b/AsbCloudWebApi/SignalR/Services/SignalRNotificationSender.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Repositories;
+using AsbCloudApp.Services.Notifications;
+using AsbCloudWebApi.SignalR.ConnectionManager;
+using Microsoft.AspNetCore.SignalR;
+
+namespace AsbCloudWebApi.SignalR.Services;
+
+public class SignalRNotificationSender : INotificationSender
+{
+ private readonly IConnectionManager connectionManager;
+ private readonly IHubContext notificationHubContext;
+ private readonly INotificationRepository notificationRepository;
+
+ public SignalRNotificationSender(IConnectionManager connectionManager,
+ IHubContext notificationHubContext,
+ INotificationRepository notificationRepository)
+ {
+ this.connectionManager = connectionManager;
+ this.notificationHubContext = notificationHubContext;
+ this.notificationRepository = notificationRepository;
+ }
+
+ public NotificationTransport NotificationTransport => NotificationTransport.SignalR;
+
+ public async Task SendAsync(NotificationDto notification,
+ CancellationToken cancellationToken)
+ {
+ const string method = "notifications";
+
+ var connectionId = connectionManager.GetConnectionIdByUserId(notification.IdUser);
+
+ if (!string.IsNullOrWhiteSpace(connectionId))
+ {
+ await notificationHubContext.Clients.Client(connectionId)
+ .SendAsync(method,
+ notification,
+ cancellationToken);
+
+ notification.SentDate = DateTime.UtcNow;
+ notification.NotificationState = NotificationState.Sent;
+ }
+
+ await notificationRepository.UpdateAsync(notification,
+ cancellationToken);
+ }
+
+ public async Task SendRangeAsync(IEnumerable notifications,
+ CancellationToken cancellationToken)
+ {
+ foreach (var notification in notifications)
+ {
+ await SendAsync(notification,
+ cancellationToken);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Startup.cs b/AsbCloudWebApi/Startup.cs
index 3e1c56c3..bda1e1ff 100644
--- a/AsbCloudWebApi/Startup.cs
+++ b/AsbCloudWebApi/Startup.cs
@@ -1,9 +1,7 @@
using AsbCloudInfrastructure;
using AsbCloudWebApi.Converters;
using AsbCloudWebApi.Middlewares;
-using AsbCloudWebApi.Options.Notifications;
using AsbCloudWebApi.SignalR;
-using AsbCloudWebApi.SignalR.BackgroundServices;
using AsbCloudWebApi.SignalR.ConnectionManager;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -44,13 +42,13 @@ namespace AsbCloudWebApi
services.AddSwagger();
services.AddInfrastructure(Configuration);
+
+ services.AddNotificationSenders();
services.AddJWTAuthentication();
services.AddSignalR()
- .Services.AddSingleton()
- .AddHostedService()
- .Configure(Configuration.GetSection("NotificationsOptionsSignalR"));
+ .Services.AddSingleton();
services.AddCors(options =>
{