Blazor WASM中如何在单例服务中使用命名HttpClient
在Singleton服务中使用命名HttpClient的正确方式
问题根源
你遇到的错误是因为Singleton服务的生命周期长于Scoped服务,DI容器禁止从Singleton服务中直接消费Scoped服务,防止出现服务实例过期或资源泄漏的问题。你的代码中通过AddScoped注册了命名HttpClient,而MyApiService是Singleton,直接注入就触发了这个限制。
推荐解决方案:注入IHttpClientFactory
最安全且符合设计的方式是直接将IHttpClientFactory注入到Singleton服务中,每次需要调用API时通过工厂创建命名HttpClient。IHttpClientFactory本身是Singleton生命周期,完全可以安全注入到Singleton服务里,且工厂会自动管理HttpClient的连接池和生命周期。
修改MyApiService代码
public class MyApiService : IMyApiService { private readonly IHttpClientFactory _httpClientFactory; public MyApiService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<List<Customer>> GetCustomers() { // 每次调用时获取配置好的命名HttpClient var myApiHttpClient = _httpClientFactory.CreateClient("MyApi"); var response = await myApiHttpClient.GetAsync("/customers"); if(!response.IsSuccessStatusCode) throw new Exception("API call failed!"); var json = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize<List<Customer>>(json); } }
简化Program.cs注册
不需要额外注册Scoped的HttpClient,保留命名HttpClient和Singleton服务的注册即可:
... // 注册命名HttpClient builder.Services.AddHttpClient("MyApi", client => client.BaseAddress = new Uri("https://api.test.com")) .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>(); // 注册Singleton服务 builder.Services.AddSingleton<IMyApiService, MyApiService>(); await builder.Build().RunAsync();
备选方案:将命名HttpClient注册为Singleton(不推荐)
如果坚持要在构造函数中注入HttpClient实例,可以把命名HttpClient的注册改为Singleton:
builder.Services.AddSingleton(sp => sp.GetRequiredService<IHttpClientFactory>() .CreateClient("MyApi"));
但这种方式存在隐患:Singleton的HttpClient实例会长期持有底层Handler,无法自动刷新DNS缓存或处理连接池的动态调整,可能导致后续请求出现异常,因此不推荐使用。
关于Blazor WASM的补充
虽然Blazor WASM中Singleton和Scoped服务在浏览器环境下行为近似,但遵循通用的DI生命周期规则能保证代码的可移植性(比如迁移到Blazor Server时不会出现问题),因此推荐使用第一种方案。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

