Отправка уведомлений

1. Сделал отправку уведомлений через SignalR.
2. Сделал рефакторинг для хабов.
This commit is contained in:
parent 96786b1be7
commit 29a534258e
10 changed files with 200 additions and 17 deletions

View File

@ -0,0 +1,8 @@
namespace AsbCloudWebApi.Options.Notifications;
public class NotificationsOptionsSignalR
{
public string Method { get; set; } = null!;
public int IdTransport { get; set; }
}

View File

@ -0,0 +1,82 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudWebApi.Options.Notifications;
using AsbCloudWebApi.SignalR.ConnectionManager;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace AsbCloudWebApi.SignalR.BackgroundServices;
public class SignalRNotificationSender : BackgroundService
{
private readonly IConnectionManager connectionManager;
private readonly INotificationSendingQueueService notificationSendingQueueService;
private readonly IHubContext<NotificationHub> notificationHubContext;
private readonly NotificationsOptionsSignalR notificationsOptionsSignalR;
private readonly IServiceProvider serviceProvider;
public SignalRNotificationSender(IConnectionManager connectionManager,
INotificationSendingQueueService notificationSendingQueueService,
IHubContext<NotificationHub> notificationHubContext,
IOptions<NotificationsOptionsSignalR> notificationsOptionsSignalR,
IServiceProvider serviceProvider)
{
this.connectionManager = connectionManager;
this.notificationSendingQueueService = notificationSendingQueueService;
this.notificationHubContext = notificationHubContext;
this.notificationsOptionsSignalR = notificationsOptionsSignalR.Value;
this.serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Run( async () =>
{
await SendAsync(stoppingToken);
}, stoppingToken);
}
private async Task SendAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
notificationSendingQueueService.Wait(cancellationToken);
while (!notificationSendingQueueService.IsEmpty)
{
if (notificationSendingQueueService.TryDequeue(out var notification))
{
string userId = notification.IdUser.ToString();
var connectionId = connectionManager.GetConnectionIdByUserId(userId);
if (!string.IsNullOrWhiteSpace(connectionId))
{
await notificationHubContext.Clients.Client(connectionId)
.SendAsync(notificationsOptionsSignalR.Method,
notification,
cancellationToken);
notification.SentDateAtUtc = DateTime.UtcNow;
notification.IsRead = false;
}
var scope = serviceProvider.CreateScope();
var notificationRepository = scope.ServiceProvider.GetService<INotificationRepository>();
if (notificationRepository != null)
{
await notificationRepository.UpdateAsync(notification,
cancellationToken);
}
}
}
}
}
}

View File

@ -0,0 +1,19 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace AsbCloudWebApi.SignalR;
public abstract class BaseHub : Hub
{
public virtual Task AddToGroup(string groupName) =>
Groups.AddToGroupAsync(Context.ConnectionId, groupName);
public virtual Task RemoveFromGroup(string groupName) =>
Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public abstract class BaseHub<T> : BaseHub
where T : class
{
}

View File

@ -0,0 +1,25 @@
using System.Collections.Concurrent;
namespace AsbCloudWebApi.SignalR.ConnectionManager;
public class ConnectionManager : IConnectionManager
{
private readonly ConcurrentDictionary<string, string> _connections = new();
public void AddConnection(string userId,
string connectionId)
{
_connections.TryAdd(userId, connectionId);
}
public void RemoveConnection(string userId)
{
_connections.TryRemove(userId, out _);
}
public string? GetConnectionIdByUserId(string userId)
{
_connections.TryGetValue(userId, out string? connectionId);
return connectionId;
}
}

View File

@ -0,0 +1,11 @@
namespace AsbCloudWebApi.SignalR.ConnectionManager;
public interface IConnectionManager
{
void AddConnection(string userId,
string connectionId);
void RemoveConnection(string userId);
string? GetConnectionIdByUserId(string userId);
}

View File

@ -0,0 +1,39 @@
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Services;
using AsbCloudWebApi.Options.Notifications;
using AsbCloudWebApi.SignalR.ConnectionManager;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
namespace AsbCloudWebApi.SignalR;
[Authorize]
public class NotificationHub : BaseHub
{
private readonly IConnectionManager connectionManager;
private readonly INotificationService notificationService;
private readonly NotificationsOptionsSignalR notificationsOptionsSignalR;
public NotificationHub(IConnectionManager connectionManager,
INotificationService notificationService,
IOptions<NotificationsOptionsSignalR> notificationsOptionsSignalR)
{
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);
await notificationService.ResendNotificationAsync(idUser,
notificationsOptionsSignalR.IdTransport,
CancellationToken.None);
await base.OnConnectedAsync();
}
}

View File

@ -1,6 +1,4 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR
{
@ -8,12 +6,8 @@ namespace AsbCloudWebApi.SignalR
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
[Authorize]
public class ReportsHub : Hub<IReportHubClient>
public class ReportsHub : BaseHub<IReportHubClient>
{
public Task AddToGroup(string groupName)
=> Groups.AddToGroupAsync(Context.ConnectionId, groupName);
public Task RemoveFromGroup(string groupName)
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
}

View File

@ -1,6 +1,4 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace AsbCloudWebApi.SignalR
{
@ -8,12 +6,8 @@ namespace AsbCloudWebApi.SignalR
// https://docs.microsoft.com/ru-ru/aspnet/core/signalr/introduction?view=aspnetcore-5.0
[Authorize]
public class TelemetryHub : Hub
public class TelemetryHub : BaseHub
{
public Task AddToGroup(string groupName)
=> Groups.AddToGroupAsync(Context.ConnectionId, groupName.ToString());
public Task RemoveFromGroup(string groupName)
=> Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
}

View File

@ -1,7 +1,10 @@
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;
using Microsoft.Extensions.Configuration;
@ -44,7 +47,10 @@ namespace AsbCloudWebApi
services.AddJWTAuthentication();
services.AddSignalR();
services.AddSignalR()
.Services.AddSingleton<IConnectionManager, ConnectionManager>()
.AddHostedService<SignalRNotificationSender>()
.Configure<NotificationsOptionsSignalR>(Configuration.GetSection("NotificationsOptionsSignalR"));
services.AddCors(options =>
{
@ -147,6 +153,7 @@ namespace AsbCloudWebApi
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/hubs/notifications");
endpoints.MapHub<TelemetryHub>("/hubs/telemetry");
endpoints.MapHub<ReportsHub>("/hubs/reports");
});

View File

@ -27,6 +27,10 @@
"supportMail": "support@digitaldrilling.ru"
},
"DirectoryNameHelpPageFiles": "helpPages",
"NotificationsOptionsSignalR": {
"Method": "notifications",
"IdTransport": 1
},
"Urls": "http://0.0.0.0:5000" //;https://0.0.0.0:5001" //,
// See https man: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0
//"Kestrel": {