You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor Server应用中强制关闭特定Circuit?

在Blazor Server中强制关闭特定Circuit(踢除用户)的方法

要实现强制关闭特定Circuit,核心思路是自定义CircuitHandler跟踪所有活跃的Circuit实例,然后通过调用Circuit的DisposeAsync()方法主动终止连接。具体步骤如下:

1. 自定义CircuitHandler并跟踪活跃Circuits

创建继承自CircuitHandler的自定义类,用线程安全集合维护所有活跃Circuit的引用:

using Microsoft.AspNetCore.Components.Server.Circuits;
using System.Collections.Concurrent;

public class TrackedCircuitHandler : CircuitHandler
{
    // 存储CircuitId与对应Circuit实例的映射
    private readonly ConcurrentDictionary<string, Circuit> _activeCircuits = new();
    // 存储用户ID与CircuitId的关联(用于按用户踢除)
    private readonly ConcurrentDictionary<string, string> _userCircuitMap = new();

    // 对外暴露只读的活跃Circuit列表
    public IReadOnlyDictionary<string, Circuit> ActiveCircuits => _activeCircuits;

    public override async Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        _activeCircuits.TryAdd(circuit.Id, circuit);
        
        // 关联用户ID与CircuitId(需注入AuthenticationStateProvider)
        var authState = await circuit.HttpContext.RequestServices
            .GetRequiredService<AuthenticationStateProvider>()
            .GetAuthenticationStateAsync();
        var userId = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        if (!string.IsNullOrEmpty(userId))
        {
            _userCircuitMap.TryAdd(userId, circuit.Id);
        }

        await base.OnCircuitOpenedAsync(circuit, cancellationToken);
    }

    public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken)
    {
        _activeCircuits.TryRemove(circuit.Id, out _);
        
        // 清理用户与Circuit的关联
        var userId = _userCircuitMap.FirstOrDefault(kv => kv.Value == circuit.Id).Key;
        if (!string.IsNullOrEmpty(userId))
        {
            _userCircuitMap.TryRemove(userId, out _);
        }

        return base.OnCircuitClosedAsync(circuit, cancellationToken);
    }

    // 按CircuitId强制关闭
    public async Task ForceCloseCircuitAsync(string circuitId)
    {
        if (_activeCircuits.TryGetValue(circuitId, out var circuit))
        {
            await circuit.DisposeAsync();
            _activeCircuits.TryRemove(circuitId, out _);
        }
    }

    // 按用户ID强制关闭对应的Circuit
    public async Task ForceCloseUserCircuitAsync(string userId)
    {
        if (_userCircuitMap.TryGetValue(userId, out var circuitId))
        {
            await ForceCloseCircuitAsync(circuitId);
        }
    }
}

2. 注册自定义CircuitHandler到服务容器

在Program.cs中注册该Handler,确保被Blazor Server框架加载:

var builder = WebApplication.CreateBuilder(args);

// 注册自定义CircuitHandler
builder.Services.AddSingleton<TrackedCircuitHandler>();
builder.Services.AddSingleton<CircuitHandler>(sp => 
    sp.GetRequiredService<TrackedCircuitHandler>());

// 其他服务注册(如Blazor组件、身份验证等)
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddAuthentication();

var app = builder.Build();

// 中间件配置
app.UseAuthentication();
app.UseAuthorization();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

3. 调用强制关闭方法

可以在任意服务或组件中注入TrackedCircuitHandler,执行踢除操作:

示例:在后台服务中踢除指定用户

public class UserManagementService
{
    private readonly TrackedCircuitHandler _circuitHandler;

    public UserManagementService(TrackedCircuitHandler circuitHandler)
    {
        _circuitHandler = circuitHandler;
    }

    // 踢除指定用户
    public async Task KickUserAsync(string userId)
    {
        await _circuitHandler.ForceCloseUserCircuitAsync(userId);
    }
}

示例:在Blazor组件中踢除当前用户

@inject TrackedCircuitHandler CircuitHandler
@inject AuthenticationStateProvider AuthStateProvider

<button @onclick="KickCurrentUser" class="btn btn-danger">踢除自己</button>

@code {
    private async Task KickCurrentUser()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        var userId = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        if (!string.IsNullOrEmpty(userId))
        {
            await CircuitHandler.ForceCloseUserCircuitAsync(userId);
        }
    }
}

关键注意事项

  • 调用Circuit.DisposeAsync()会立即终止Blazor连接,前端默认会触发重连逻辑,若需阻止重连,可在前端监听onclose事件并自定义处理。
  • 多用户场景下,需确保用户ID与CircuitId的关联存储是线程安全的,避免并发操作导致的异常。

内容的提问来源于stack exchange,提问作者Pawel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:15:20