首页 > 解决方案 > Blazor - IHttpClientFactory.CreateClient 上的“指定转换无效”

问题描述

现在我正在尝试在 Blazor WASM 中实现绝对基本的(假)身份验证。我使用 .Net 5.0 和身份验证创建了一个 Visual Studio“Blazor Webassembly App”项目。我剥离了除 Index.razor 之外的 .razor 文件,它得到了以下实现

@page "/"
@inherits DataLayerGeneratorClient.Pages.Main.IndexBase

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="Logout">
            Log out
        </button>
    </Authorized>
    <NotAuthorized>
        <table>
            <tr>
                <td>User</td>
                <td><input type="text" @bind="AuthenticationStateProvider.User" /></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type="text" @bind="AuthenticationStateProvider.Password" /></td>
            </tr>
        </table>
        <br />
        <button @onclick="Login">Login</button>
    </NotAuthorized>
</AuthorizeView>

和 IndexBase.cs

public class IndexBase : LayoutComponentBase
{
    [Inject]
    public IHttpClientFactory HttpClientFactory { get; set; }

    [Inject]
    public CustomAuthenticationStateProvider AuthenticationStateProvider { get; set; }


    public async Task Login(MouseEventArgs e)
    {
        using (HttpClient client = HttpClientFactory.CreateClient("ServerAPI"))
        {
            ...
        }
    }
}

我还做了一个 CustomAuthenticationStateProvider

public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            //Login failed
            return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));

            //Login succeeded
            //Claim claim = new Claim(ClaimTypes.Name, "TestUser");
            //ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[] { claim }, "fake auth");
            //ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
            //AuthenticationState authenticationState = new AuthenticationState(claimsPrincipal);
            //return Task.FromResult(authenticationState);
        }
}

还有一个 CustomAuthorizationMessageHandler

public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
    private readonly CustomAuthenticationStateProvider _customAuthenticationStateProvider;

    public CustomAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigation, CustomAuthenticationStateProvider customAuthenticationStateProvider) : base(provider, navigation)
    {
        if (customAuthenticationStateProvider == null)
        {
            throw new ArgumentNullException(nameof(customAuthenticationStateProvider));
        }
        _customAuthenticationStateProvider = customAuthenticationStateProvider;
    }

    ...
}

在 App.razor 我更改了 DefaultLayout

DefaultLayout="@typeof(Index)"

最后是 Program.cs 的主要内容

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");            

    builder.Services.AddApiAuthorization();
    builder.Services.AddAuthorizationCore();

    builder.Services.AddScoped<CustomAuthenticationStateProvider>();
    builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
    builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
    builder.Services.AddScoped<AuthorizationMessageHandler, CustomAuthorizationMessageHandler>();

    builder.Services.AddHttpClient("ServerAPI").AddHttpMessageHandler(sp =>
    {
        return sp.GetService<CustomAuthorizationMessageHandler>().ConfigureHandler(authorizedUrls: new[] { "http://localhost:10000" });
    });

    builder.Services.AddScoped(serviceProvider => serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient("ServerAPI"));

    await builder.Build().RunAsync();
}

现在的问题。一旦 IHttpClientFactory.CreateHttpClient 被执行,它就会失败并显示错误“指定的强制转换无效”。什么演员表无效?

编辑 1 注入 HttpClient 而不是 IHttpClientFactory 似乎不是答案。当我测试它时,错误只是在启动而不是单击按钮时出现。如果有帮助,这里又是堆栈跟踪

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=5.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteUserAccount, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=5.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[Microsoft.AspNetCore.Components.WebAssembly.Authentication.ApiAuthorizationProviderOptions, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=5.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].<AddRemoteAuthentication>b__0_1(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__1(ServiceProviderEngineScope p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[CustomAuthorizationMessageHandler](IServiceProvider provider)
   at DataLayerGeneratorClient.Program.<>c.<Main>b__0_0(IServiceProvider sp) in D:\Dev\4.0\Test2\DataLayerGenerat…tem.Lazy`1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].CreateValue()
   at System.Lazy`1[[Microsoft.Extensions.Http.ActiveHandlerTrackingEntry, Microsoft.Extensions.Http, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].get_Value()
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler(String name)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient(String name)
   at DataLayerGeneratorClient.Program.<>c.<Main>b__0_1(IServiceProvider serviceProvider) in D:\Dev\4.0\Test2\DataLayerGeneratorClient\Program.cs:line 32
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__1(ServiceProviderEngineScope p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass6_0.<CreateInitializer>g__Initialize|2(IServiceProvider serviceProvider, IComponent component)
   at Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
   at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateComponent(Type componentType)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame& frame, Int32 parentComponentId)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()…

编辑 2 一旦我删除对 CustomAuthenticationStateProvider 的任何引用,错误就消失了。但这有什么意义呢?

编辑 3 我通过删除 AddApiAuthorization 并实现自定义 HttpMessageHandler 而不是 cucstom AuthorizationMessageHandler 使其工作

标签: c#authenticationblazorwebassemblycustom-authentication

解决方案


推荐阅读