Blazor Server中DelegatingHandler访问DI服务异常问题咨询
问题原因
你遇到的问题核心是Blazor Server的作用域模型与HttpClient及DelegatingHandler的生命周期不匹配导致的:
IHttpContextAccessor的局限性:Blazor Server中,HttpContext仅在初始HTTP渲染组件时有效,后续按钮点击等SignalR交互属于电路(Circuit)上下文,此时HttpContext可能已失效,或其RequestServices并非当前电路的作用域,导致无法获取Scoped的TokenProvider。- Handler生命周期冲突:通过
AddHttpMessageHandler<T>注册的AuthenticationStateHandler默认会被解析为Singleton(与HttpClient的Singleton生命周期匹配),而TokenProvider是Scoped服务。Singleton的Handler无法可靠获取当前电路作用域的Scoped服务,第一次调用可能碰巧复用了初始请求的上下文,第二次调用时上下文已失效,导致GetService<TokenProvider>()返回null。
解决方案
不要依赖IHttpContextAccessor获取作用域服务,改用IServiceScopeFactory在每次请求时创建当前作用域,确保能获取到正确的TokenProvider:
- 修改
AuthenticationStateHandler,注入IServiceScopeFactory替代IHttpContextAccessor:
public class AuthenticationStateHandler : DelegatingHandler { private readonly IServiceScopeFactory _scopeFactory; public AuthenticationStateHandler(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { using var scope = _scopeFactory.CreateScope(); var tokenProvider = scope.ServiceProvider.GetRequiredService<TokenProvider>(); var token = await tokenProvider.GetAccessTokenAsync(); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); return await base.SendAsync(request, cancellationToken); } }
- 将
AuthenticationStateHandler注册为Scoped服务,并调整HttpClient的注册方式:
// 注册Scoped的Handler services.AddScoped<AuthenticationStateHandler>(); // 为每个HttpClient注入Scoped的Handler实例 services.AddHttpClient<DocumentClient>() .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthenticationStateHandler>()); services.AddHttpClient<DocumentAttachmentClient>() .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthenticationStateHandler>());
- 确保
TokenProvider是Scoped注册(这应该是你当前的注册方式):
services.AddScoped<TokenProvider>();
这样修改后,每次HTTP请求都会创建一个新的作用域,获取当前电路上下文的TokenProvider,无论调用哪个HttpClient,都能可靠获取到令牌。
内容的提问来源于stack exchange,提问作者Martin Holý
相关产品推荐
相关产品推荐

