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:
@@ -1,5 +1,6 @@
|
||||
@page "/dashboard"
|
||||
@page "/dashboards/{DashboardId?}"
|
||||
@implements IAsyncDisposable
|
||||
@inject Microsoft.Extensions.Configuration.IConfiguration Configuration
|
||||
@inject NavigationManager Navigation
|
||||
@inject DashboardApiClient DashboardApi
|
||||
@@ -77,19 +78,38 @@
|
||||
[SupplyParameterFromQuery] public string? Mode { get; set; }
|
||||
|
||||
private readonly List<DashboardInfoDto> dashboards = new();
|
||||
private HubConnection? _hubConnection;
|
||||
|
||||
private bool IsDesigner => !string.Equals(Mode, "viewer", StringComparison.OrdinalIgnoreCase);
|
||||
private WorkingMode CurrentMode => IsDesigner ? WorkingMode.Designer : WorkingMode.ViewerOnly;
|
||||
private string SelectedDashboardId { get; set; } = "";
|
||||
private string SelectedDashboardId { get; set; } = string.Empty;
|
||||
private string DashboardKey => $"{SelectedDashboardId}-{(IsDesigner ? "designer" : "viewer")}";
|
||||
|
||||
private string DashboardEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/api/dashboard";
|
||||
private string HubEndpoint => $"{Configuration["ApiBaseUrl"]?.TrimEnd('/')}/hubs/dashboards";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await RefreshDashboards();
|
||||
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(HubEndpoint)
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
_hubConnection.On("DashboardsChanged", async () =>
|
||||
{
|
||||
await RefreshDashboards();
|
||||
});
|
||||
|
||||
await _hubConnection.StartAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (dashboards.Count == 0)
|
||||
{
|
||||
dashboards.AddRange(await DashboardApi.GetAllAsync());
|
||||
await RefreshDashboards();
|
||||
}
|
||||
|
||||
var requestedId = string.IsNullOrWhiteSpace(DashboardId) || string.Equals(DashboardId, "default", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -119,4 +139,25 @@
|
||||
var targetMode = IsDesigner ? "viewer" : "designer";
|
||||
Navigation.NavigateTo($"dashboards/{SelectedDashboardId}?mode={targetMode}", replace: true);
|
||||
}
|
||||
|
||||
private async Task RefreshDashboards()
|
||||
{
|
||||
var latest = await DashboardApi.GetAllAsync();
|
||||
if (latest.Count == dashboards.Count && latest.All(d => dashboards.Any(x => x.Id == d.Id && x.Name == d.Name)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dashboards.Clear();
|
||||
dashboards.AddRange(latest);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (_hubConnection != null)
|
||||
{
|
||||
await _hubConnection.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using Microsoft.AspNetCore.SignalR.Client
|
||||
@using DbFirst.BlazorWebApp
|
||||
@using DbFirst.BlazorWebApp.Components
|
||||
@using DbFirst.BlazorWebApp.Models
|
||||
|
||||
@@ -12,5 +12,9 @@
|
||||
<PackageReference Include="DevExpress.Blazor.Themes" Version="25.2.3" />
|
||||
<PackageReference Include="DevExpress.Blazor.Themes.Fluent" Version="25.2.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DevExpress.Blazor" Version="25.2.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.22" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user