在Blazor WASM中用Refit添加令牌时遇类型转换异常
问题重现
注册代码
var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddHttpClient("myApi").AddHttpMessageHandler<CustomAuthorizationMessageHandler>(); builder.Services.AddScoped<CustomAuthorizationMessageHandler>(); builder.Services.AddAuthorizationCore(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped<AuthenticationStateProvider, PersistentAuthenticationStateProvider>(); builder.Services.AddApiAuthorization(); builder.Services.AddRefitClient<IWeatherApi>() .ConfigureHttpClient(c => { c.BaseAddress = new Uri("https://localhost:7252"); }) .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>() .ConfigureHandler(new[] { "https://localhost:7252" }));
尝试的替代调用方式
RestService.For<IWeatherApi>(HttpClientFactory.CreateClient("myApi"));
错误信息
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Specified cast is not valid.
System.InvalidCastException: Specified cast is not valid.at Microsoft.Extensions.DependencyInjection.WebAssemblyAuthenticationServiceCollectionExtensions.<>c__0`3[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationState, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteUserAccount, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.AspNetCore.Components.WebAssembly.Authentication.ApiAuthorizationProviderOptions, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].b__0_0(IServiceProvider sp)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
问题原因
核心矛盾是**PersistentAuthenticationStateProvider与AddApiAuthorization()的默认服务实现不兼容**:
AddApiAuthorization()会自动注册一套完整的远程认证服务,包括特定的AuthenticationStateProvider子类(RemoteAuthenticationStateProvider)- 你手动注册的
PersistentAuthenticationStateProvider未继承该子类,框架尝试将其强制转换为所需类型时抛出转换异常。
解决步骤
1. 调整认证状态提供者注册
方案一:使用AddApiAuthorization()默认配置(推荐)
移除手动替换的PersistentAuthenticationStateProvider,让框架自动配置兼容的认证服务:
// 移除该行手动注册 // builder.Services.AddScoped<AuthenticationStateProvider, PersistentAuthenticationStateProvider>(); // 保留AddApiAuthorization(),它会自动注册正确的AuthenticationStateProvider builder.Services.AddApiAuthorization();
方案二:自定义兼容的状态提供者
若必须使用自定义逻辑,需确保类继承自框架要求的基类:
public class CustomPersistentAuthenticationStateProvider : RemoteAuthenticationStateProvider<RemoteAuthenticationState, RemoteUserAccount> { // 实现自定义状态管理逻辑 } // 注册时替换对应服务类型 builder.Services.AddScoped<RemoteAuthenticationStateProvider<RemoteAuthenticationState, RemoteUserAccount>, CustomPersistentAuthenticationStateProvider>();
2. 统一HttpClient认证处理器
保持命名HttpClient与Refit客户端的认证逻辑一致:
- 如果使用自定义
CustomAuthorizationMessageHandler,Refit客户端也应添加该处理器 - 如果依赖
AddApiAuthorization()的默认处理器,需确保正确关联
调整Refit客户端注册示例:
builder.Services.AddRefitClient<IWeatherApi>() .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://localhost:7252")) .AddHttpMessageHandler<CustomAuthorizationMessageHandler>(); // 与命名客户端使用相同的处理器
3. 正确获取HttpClient
在Blazor WebAssembly中,通过依赖注入获取客户端,而非直接调用HttpClientFactory.CreateClient,确保服务容器正确解析所有依赖:
// 在组件或服务中通过构造函数注入 public class WeatherService { private readonly IWeatherApi _weatherApi; public WeatherService(IWeatherApi weatherApi) { _weatherApi = weatherApi; } // 使用_weatherApi调用接口 }
内容的提问来源于stack exchange,提问作者Larsi

