fix(admin): stop SignalR hub-connect failure from crashing cluster pages
The Admin-003 fix gated every SignalR hub with [Authorize]/RequireAuthorization, but the server-side HubConnection clients on ClusterDetail, AclsTab, RedundancyTab and RoleGrants cannot forward the browser's HttpOnly auth cookie — so the hub negotiate returns 401. Those four pages called HubConnection.StartAsync() unguarded, so the 401 surfaced as an unhandled exception (a 500 page for the prerendered ClusterDetail, a broken circuit for the others). Wrap StartAsync/SendAsync in try/catch on all four, matching the established best-effort pattern already used in Hosts.razor and ScriptLog.razor: the live banner / live refresh degrades but the page renders. Restoring functional hub live-updates needs a token-based hub auth scheme (cookie forwarding is not viable across the prerender/interactive boundary) and is left as follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -232,9 +232,19 @@ else
|
||||
_acls = await AclSvc.ListAsync(GenerationId, CancellationToken.None);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
// Best-effort: FleetStatusHub requires an authenticated caller, and the server-side
|
||||
// HubConnection cannot forward the browser auth cookie — swallow connect failures so
|
||||
// the tab still renders. Live ACL-change updates degrade.
|
||||
try
|
||||
{
|
||||
await _hub.StartAsync();
|
||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// best-effort live updates — see comment above
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
|
||||
@@ -192,9 +192,19 @@ else
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
|
||||
// Best-effort: FleetStatusHub requires an authenticated caller, and the server-side
|
||||
// HubConnection cannot forward the browser auth cookie — a connect failure must not
|
||||
// crash the page. Live banner updates degrade; the page still renders.
|
||||
try
|
||||
{
|
||||
await _hub.StartAsync();
|
||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// best-effort live updates — see comment above
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateDraftAsync()
|
||||
{
|
||||
|
||||
@@ -143,9 +143,19 @@ else
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
|
||||
// Best-effort: FleetStatusHub requires an authenticated caller, and the server-side
|
||||
// HubConnection cannot forward the browser auth cookie — swallow connect failures so
|
||||
// the tab still renders. Live role-change updates degrade.
|
||||
try
|
||||
{
|
||||
await _hub.StartAsync();
|
||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// best-effort live updates — see comment above
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
|
||||
@@ -180,9 +180,19 @@ else
|
||||
await ReloadAsync();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
// Best-effort: FleetStatusHub requires an authenticated caller, and the server-side
|
||||
// HubConnection cannot forward the browser auth cookie — swallow connect failures so
|
||||
// the page still renders. Live role-grant updates degrade.
|
||||
try
|
||||
{
|
||||
await _hub.StartAsync();
|
||||
await _hub.SendAsync("SubscribeFleet");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// best-effort live updates — see comment above
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user