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);
|
_acls = await AclSvc.ListAsync(GenerationId, CancellationToken.None);
|
||||||
await InvokeAsync(StateHasChanged);
|
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.StartAsync();
|
||||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// best-effort live updates — see comment above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -192,9 +192,19 @@ else
|
|||||||
await InvokeAsync(StateHasChanged);
|
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.StartAsync();
|
||||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// best-effort live updates — see comment above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CreateDraftAsync()
|
private async Task CreateDraftAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -143,9 +143,19 @@ else
|
|||||||
await InvokeAsync(StateHasChanged);
|
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.StartAsync();
|
||||||
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
await _hub.SendAsync("SubscribeCluster", ClusterId);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// best-effort live updates — see comment above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -180,9 +180,19 @@ else
|
|||||||
await ReloadAsync();
|
await ReloadAsync();
|
||||||
await InvokeAsync(StateHasChanged);
|
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.StartAsync();
|
||||||
await _hub.SendAsync("SubscribeFleet");
|
await _hub.SendAsync("SubscribeFleet");
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// best-effort live updates — see comment above
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user