You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor SSR页面使用MudBlazor提交表单时出现EditForm参数缺失错误的解决方法

Blazor SSR页面使用MudBlazor提交表单时出现EditForm参数缺失错误的解决方法

问题原因分析

你遇到的错误是因为在Blazor SSR页面中,EditForm配置了传统HTML表单的method="post"属性,这会触发浏览器的原生表单提交流程,而非Blazor的交互式表单处理逻辑。在这个过程中Blazor组件上下文无法正确传递,导致EditForm找不到指定的Model参数。另外你绑定了仅在表单验证失败时触发的OnInvalidSubmit事件,却未处理验证通过后的提交逻辑,进一步加剧了流程混乱。

具体修复步骤

1. 移除EditForm的method="post"属性

Blazor SSR的EditForm不需要传统的method="post",它会通过内置的交互式机制处理表单提交。移除该属性后,表单会遵循Blazor的组件逻辑运行,避免上下文丢失。

2. 绑定正确的提交事件

将OnInvalidSubmit替换为OnValidSubmit,因为你需要在表单验证通过后执行登录逻辑。OnInvalidSubmit仅在输入不符合验证规则时触发,不是处理正常登录的正确事件。

3. 修复登录逻辑中的硬编码密码

你的SubmitDetails方法里硬编码了密码"admin@123",完全忽略了用户输入的密码,这会导致登录逻辑失效,需要改为使用用户输入的Input.Password。

4. 完善密码显示/隐藏功能(可选)

你之前定义了ButtonTestclick方法但未绑定到任何按钮,导致密码框的显示/隐藏功能无法使用,我们可以补全这部分交互提升体验。

修改后的完整代码

页面渲染部分

@layout EmptyLayout
@page "/Account/login"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@inject UserManager<User> UserManager
@inject SignInManager<User> SignInManager
@inject ISnackbar _snackbar
@inject NavigationManager _navigation
@inject IdentityRedirectManager RedirectManager

<PageTitle>Log in</PageTitle>

<div class="d-flex flex-grow-1 mud-width-full align-center justify-center" style="min-height:100vh">
    <EditForm Model="Input" OnValidSubmit="SubmitDetails" FormName="login">
        <DataAnnotationsValidator />
        <MudText Typo="Typo.h2" Align="Align.Center" Class="mb-3" Color="Color.Primary">Rosui</MudText>

        <MudStack Spacing="3" AlignItems="AlignItems.Center" Justify="Justify.Center">
            <MudTextField 
                @bind-Value="Input.Email" 
                Variant="Variant.Outlined" 
                For="(() => Input.Email)" 
                Style="min-width:300px">
            </MudTextField>

            <MudStack Spacing="0" Justify="Justify.Center" AlignItems="AlignItems.End">
                <MudTextField 
                    @bind-Value="Input.Password" 
                    For="(() => Input.Password)" 
                    Variant="Variant.Outlined" 
                    Style="min-width:300px"
                    InputType="@PasswordInput"
                    Adornment="Adornment.End"
                    AdornmentIcon="@PasswordInputIcon"
                    OnAdornmentClick="ButtonTestclick">
                </MudTextField>
                <MudButton Variant="Variant.Text" Color="Color.Dark" Size="Size.Small" Class="pa-0 ma-0">
                    <MudText Typo="Typo.caption">Forgot Password?</MudText>
                </MudButton>
            </MudStack>

            <MudButton 
                Variant="Variant.Filled" 
                Color="Color.Primary"
                Disabled="@_processing" 
                ButtonType="ButtonType.Submit" 
                Style="width:200px" 
                Class="mb-6">
                @if (_processing)
                {
                    <MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true"></MudProgressCircular>
                }
                else
                {
                    <MudText>Login</MudText>
                }
            </MudButton>
        </MudStack>
    </EditForm>
</div>

逻辑处理部分

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    protected override async Task OnInitializedAsync()
    {
        if (HttpMethods.IsGet(HttpContext.Request.Method))
        {
            // 清除现有外部Cookie,确保登录流程干净
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
        }
    }

    InputType PasswordInput = InputType.Password;
    string PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
    bool isShow;

    void ButtonTestclick()
    {
        if (isShow)
        {
            isShow = false;
            PasswordInputIcon = Icons.Material.Filled.VisibilityOff;
            PasswordInput = InputType.Password;
        }
        else
        {
            isShow = true;
            PasswordInputIcon = Icons.Material.Filled.Visibility;
            PasswordInput = InputType.Text;
        }
    }

    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    [SupplyParameterFromForm]
    private InputModel Input { get; set; } = new();

    bool _processing = false;

    async Task SubmitDetails()
    {
        try
        {
            _processing = true;
            var user = await UserManager.FindByEmailAsync(Input.Email) 
                ?? throw new Exception("Login Credentials Not Found");

            // 使用用户输入的密码执行登录
            var result = await SignInManager.PasswordSignInAsync(
                user, 
                Input.Password, 
                Input.RememberMe, 
                lockoutOnFailure: false);

            if (!result.Succeeded)
            {
                throw new Exception("Login Credentials Are Wrong");
            }

            RedirectManager.RedirectTo(ReturnUrl);
        }
        catch (Exception ex)
        {
            _snackbar.Add(ex.Message, Severity.Error);
        }
        finally
        {
            _processing = false;
        }
    }

    public async Task Enter(KeyboardEventArgs e)
    {
        if (e.Key == "Enter" || e.Key == "NumpadEnter")
        {
            await SubmitDetails();
        }
    }

    private sealed class InputModel
    {
        [Required]
        [EmailAddress]
        public string Email { get; set; } = "";

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; } = "";

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
    }
}

额外说明

  • 我们给密码输入框添加了Adornment相关属性,绑定到你之前定义的ButtonTestclick方法,实现了密码显示/隐藏的交互。
  • 完善了登录结果的判断逻辑,之前的代码直接假设result不为空,现在会检查result.Succeeded来确认登录是否成功。
  • 改用OnValidSubmit确保只有验证通过的表单才会触发登录流程,避免无效提交。

备注:内容来源于stack exchange,提问作者Muheeb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 09:03:14