在一个新的 Blazor WebApp 项目中,我将尽可能多地转换 C#,以便我可以用我喜欢的语言构建尽可能多的应用程序。这几乎包括
program.cs
中的所有内容。
问题点:在
program.cs
的末尾(带有脚手架的身份和示例页面)我们发现了这个调用:
app.MapAdditionalIdentityEndpoints();
我已成功将该扩展方法中的所有内容转换为 VB.NET,并且它可以构建,但我在运行时遇到了障碍。问题集中在这个 lambda 上:
accountGroup.MapPost("/Logout", async (
ClaimsPrincipal user,
SignInManager<User> signInManager,
[FromForm] string returnUrl) =>
{
await signInManager.SignOutAsync();
return TypedResults.LocalRedirect($"~/{returnUrl}");
});
因为 VB.NET 不支持 lambda 参数上的属性(例如
<FromForm>
),所以我必须对其进行扩展:
Public Module Extensions
Private Delegate Function LogoutDelegate(
User As ClaimsPrincipal,
SignInManager As SignInManager(Of ApplicationUser),
<FromForm> ReturnUrl As String) As Task(Of RedirectHttpResult)
<Extension>
Public Function MapSomeAdditionalIdentityEndpoints(Endpoints As IEndpointRouteBuilder) As IEndpointConventionBuilder
Dim oLogoutHandler As LogoutDelegate
Dim oAccountGroup As RouteGroupBuilder
oLogoutHandler = AddressOf LogoutAsync
oAccountGroup = Endpoints.MapGroup("/Account")
oAccountGroup.MapPost("/Logout", oLogoutHandler)
Return oAccountGroup
End Function
Private Async Function LogoutAsync(
User As ClaimsPrincipal,
SignInManager As SignInManager(Of ApplicationUser),
<FromForm> ReturnUrl As String) As Task(Of RedirectHttpResult)
Await SignInManager.SignOutAsync()
Return TypedResults.LocalRedirect($"~/{ReturnUrl}")
End Function
End Module
是的,这是一个冗长的混乱,但是哦,好吧。一旦完成并开始工作,我就会想出一种方法来稍微缩减它。
当我使用此签名时,应用程序在启动时崩溃(
app.Run
)。这是完整的错误消息:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll
An action cannot use both form and JSON body parameters.
Below is the list of parameters that we found:
Parameter | Source
---------------------------------------------------------------------------------`
SignInManager | Body (Inferred)
ReturnUrl | Form (Attribute)
这似乎是有道理的,因为
SignInManager
参数没有经过专门修饰。但是,当我稍微改变签名并添加 <FromForm>
属性时,如下所示:
<FromForm> SignInManager As SignInManager(Of ApplicationUser)
...应用程序确实运行。
问题在于,当调用委托函数时,
SignInManager
为空。当我使用 <FromServices>
时,它也是空的,即使 SignInManager
很早就被注册了:
builder.Services.AddIdentityCore<User>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<Context>()
.AddSignInManager()
.AddDefaultTokenProviders();
当我运行 C# 版本的 lambda 时,这些行为都不会出现。
我不知道从哪里开始寻找解决方案。我向墙上扔一些奇怪的东西只是为了看看它是否粘住。我已经尝试了所有
From*
属性,我尝试分别从委托和函数的 <FromForm>
参数中删除 ReturnUrl
。
它会因委托上的装饰而崩溃,但不会因函数而崩溃,并且会因函数上的装饰而运行,但不会因委托而崩溃。但对于后者,当我单击“注销”按钮时,我收到 415 错误。当我移除两个装饰时,会得到 415。
将
ReturnUrl
更改为 <FromBody>
,以与 SignInManager
的推论保持一致,也会导致崩溃,尽管有一些不同的错误:
Failure to infer one or more parameters.
Below is the list of parameters that we found:
Parameter | Source
---------------------------------------------------------------------------------
SignInManager | Body (Inferred)
ReturnUrl | UNKNOWN
Did you mean to register the "UNKNOWN" parameters as a Service?
C# 版本中不会出现这种行为。
考虑到所涉及的因素,寻找这个问题的答案已被证明是毫无意义的。我认为我的情况非常罕见。
我是 Blazor 新手;我不确定这里内部发生了什么。为什么推理在我的 VB.NET 版本中导致问题,但在 C# 版本中却没有?我怎样才能运行这段代码?
我是 Blazor 新手;我不确定内部发生了什么。
事实证明,该问题与 Blazor 的内部结构关系不大,而与我的代码中的问题关系更大。我从两个不同的位置获取
IdentityUser
实例:C# 项目和 VB.NET 项目。
这当然把一切都抛之脑后了。参数
SignInManager As SignInManager(Of ApplicationUser)
返回 Nothing
是很自然的,因为该特定类型从未被注册过。一旦我将所有内容切换到一侧(在本例中为ApplicationUser
),一切就开始正常工作。
向 Aluan Haddad 指出这一点致敬。