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

Blazor Server自定义DelegatingHandler中无法获取Scoped服务怎么办

问题根本原因

DelegatingHandler的默认生命周期为单例,注册后会被IHttpClientFactory缓存复用,和Blazor Server每个用户连接对应的Circuit Scoped生命周期完全不匹配。你在构造函数注入的ITokenService是handler第一次被创建时所在请求的临时scope实例,后续不会跟着当前用户的Circuit scope更新,自然拿不到最新的token值。

解决方案

方案1:封装Scoped Api代理服务(推荐,适配Blazor生命周期)

直接弃用全局的DelegatingHandler,自己封装一个Scoped的Http请求服务,直接依赖当前Scope的ITokenService,实现最简单且不会出现生命周期不匹配问题:

  1. 定义代理服务
public interface IApiClient
{
    Task<HttpResponseMessage> GetAsync(string url, CancellationToken cancellationToken = default);
    // 按需补充Post、Put、Delete等常用请求方法
}

public class ApiClient : IApiClient
{
    private readonly HttpClient _httpClient;
    private readonly ITokenService _tokenService;

    public ApiClient(HttpClient httpClient, ITokenService tokenService)
    {
        _httpClient = httpClient;
        // 此处注入的ITokenService和App.razor、其他业务组件注入的是当前Circuit Scope下的同一个实例
        _tokenService = tokenService;
    }

    private async Task AttachAuthorizationHeaderAsync(HttpRequestMessage request)
    {
        var token = await _tokenService.TryGetToken();
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
        }
    }

    public async Task<HttpResponseMessage> GetAsync(string url, CancellationToken cancellationToken = default)
    {
        using var request = new HttpRequestMessage(HttpMethod.Get, url);
        await AttachAuthorizationHeaderAsync(request);
        return await _httpClient.SendAsync(request, cancellationToken);
    }
}
  1. 注册服务
// Program.cs 或 Startup.cs
builder.Services.AddScoped<ITokenService, TokenService>();
// 注册带配置的HttpClient
builder.Services.AddHttpClient<IApiClient, ApiClient>(client =>
{
    client.BaseAddress = new Uri("替换为你的API基础地址");
    // 可补充全局超时、默认头等配置
});
  1. 使用方式
    在需要发起请求的Blazor组件中直接注入IApiClient调用对应方法即可,所有请求会自动附加上当前用户的令牌。

方案2:改造DelegatingHandler(仅适用于令牌不存储在Circuit Scope的场景)

如果你的令牌是从独立存储(如Cookie、分布式缓存)获取,而非存在当前Circuit Scope的ITokenService实例中,可以改造DelegatingHandler每次请求时动态获取服务:

public class HttpAuthorizationHandler : DelegatingHandler
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public HttpAuthorizationHandler(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        using var scope = _serviceScopeFactory.CreateScope();
        var tokenService = scope.ServiceProvider.GetRequiredService<ITokenService>();
        var token = await tokenService.TryGetToken();

        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

注册配置:

builder.Services.AddTransient<HttpAuthorizationHandler>();
builder.Services.AddHttpClient("DefaultApiClient", client =>
{
    client.BaseAddress = new Uri("替换为你的API基础地址");
}).AddHttpMessageHandler<HttpAuthorizationHandler>();

内容的提问来源于stack exchange,提问作者Dumas.DED

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 13:15:01