Add real-time dashboard updates with SignalR

Integrate SignalR to provide real-time dashboard update notifications.
- Added DashboardsHub and DashboardChangeNotifier on the backend.
- Modified SqlDashboardStorage to trigger notifications on changes.
- Registered SignalR services and mapped the hub endpoint.
- Updated Blazor clients to connect to the hub and refresh dashboards on change.
- Added SignalR client packages and necessary DI/configuration.
This commit is contained in:
OlgunR
2026-02-04 09:01:28 +01:00
parent dbe1d9d206
commit 013088a25f
11 changed files with 138 additions and 7 deletions

View File

@@ -0,0 +1,19 @@
using DbFirst.API.Hubs;
using Microsoft.AspNetCore.SignalR;
namespace DbFirst.API.Dashboards;
public class DashboardChangeNotifier : IDashboardChangeNotifier
{
private readonly IHubContext<DashboardsHub> _hubContext;
public DashboardChangeNotifier(IHubContext<DashboardsHub> hubContext)
{
_hubContext = hubContext;
}
public void NotifyChanged()
{
_ = _hubContext.Clients.All.SendAsync("DashboardsChanged");
}
}

View File

@@ -0,0 +1,6 @@
namespace DbFirst.API.Dashboards;
public interface IDashboardChangeNotifier
{
void NotifyChanged();
}

View File

@@ -11,12 +11,14 @@ public sealed class SqlDashboardStorage : IEditableDashboardStorage
private readonly string _connectionString;
private readonly string _tableName;
private readonly Func<string?>? _userProvider;
private readonly IDashboardChangeNotifier? _notifier;
public SqlDashboardStorage(string connectionString, string tableName = "TBDD_SMF_CONFIG", Func<string?>? userProvider = null)
public SqlDashboardStorage(string connectionString, string tableName = "TBDD_SMF_CONFIG", Func<string?>? userProvider = null, IDashboardChangeNotifier? notifier = null)
{
_connectionString = connectionString;
_tableName = tableName;
_userProvider = userProvider;
_notifier = notifier;
}
public IEnumerable<DashboardInfo> GetAvailableDashboardsInfo()
@@ -98,6 +100,7 @@ public sealed class SqlDashboardStorage : IEditableDashboardStorage
connection.Open();
command.ExecuteNonQuery();
_notifier?.NotifyChanged();
return id;
}
@@ -118,6 +121,8 @@ public sealed class SqlDashboardStorage : IEditableDashboardStorage
{
throw new ArgumentException($"Dashboard '{dashboardId}' not found.");
}
_notifier?.NotifyChanged();
}
public void DeleteDashboard(string dashboardId)
@@ -128,5 +133,6 @@ public sealed class SqlDashboardStorage : IEditableDashboardStorage
connection.Open();
command.ExecuteNonQuery();
_notifier?.NotifyChanged();
}
}

View File

@@ -0,0 +1,7 @@
using Microsoft.AspNetCore.SignalR;
namespace DbFirst.API.Hubs;
public class DashboardsHub : Hub
{
}

View File

@@ -1,5 +1,6 @@
using DbFirst.API.Middleware;
using DbFirst.API.Dashboards;
using DbFirst.API.Hubs;
using DbFirst.Application;
using DbFirst.Application.Repositories;
using DbFirst.Domain;
@@ -53,6 +54,8 @@ builder.Services.AddApplication();
builder.Services.AddScoped<ICatalogRepository, CatalogRepository>();
builder.Services.AddDevExpressControls();
builder.Services.AddSignalR();
builder.Services.AddSingleton<IDashboardChangeNotifier, DashboardChangeNotifier>();
builder.Services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => {
var dashboardsPath = Path.Combine(builder.Environment.ContentRootPath, "Data", "Dashboards");
Directory.CreateDirectory(dashboardsPath);
@@ -112,7 +115,8 @@ builder.Services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvi
DashboardConfigurator configurator = new DashboardConfigurator();
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? string.Empty;
var dashboardStorage = new SqlDashboardStorage(connectionString, "TBDD_SMF_CONFIG");
var notifier = serviceProvider.GetRequiredService<IDashboardChangeNotifier>();
var dashboardStorage = new SqlDashboardStorage(connectionString, "TBDD_SMF_CONFIG", notifier: notifier);
configurator.SetDashboardStorage(dashboardStorage);
DataSourceInMemoryStorage dataSourceStorage = new DataSourceInMemoryStorage();
@@ -155,7 +159,7 @@ app.UseCors();
app.UseAuthorization();
app.MapDashboardRoute("api/dashboard", "DefaultDashboard");
app.MapHub<DashboardsHub>("/hubs/dashboards");
app.MapControllers();
app.Run();