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

ASP.NET Core表单值存在却验证失败问题求助

问题描述

用户进入页面时,表单所有字段处于禁用状态,仅显示「编辑」按钮;点击编辑按钮后表单字段启用。但此时,尽管表单字段已通过value属性填充数据,仍会显示验证失败,即使删除文本重新输入也无法重置验证状态。尝试清除验证错误后点击保存按钮,后端PageModel的Save动作仍报告表单字段无效,无法提交更新。


前端代码
<div asp-validation-summary="All"></div>
<div class="gcContent">
<div id="FormPnl">
    <form asp-page-handler="post" method="post">
        <input type="hidden" asp-for="MyInformation.Id" />
        <input type="hidden" asp-for="MyInformation.UserName" />
        <input type="hidden" asp-for="MyInformation.Email" />

        <DataAnnotationsValidator />
        <div class="validation" role="alert" asp-validation-summary="All">You received the following errors:</div>

        <p>Enter User Information</p>
        <p class="formAlerts">* Denotes a Required Field</p>
        <label asp-for="MyInformation.FirstName">First Name:* </label>
        <input @(Model.EditMode ? "" : "disabled") asp-for="MyInformation.FirstName" value="@Model.MyInformation.FirstName" class="form-control" />
        <span asp-validation-for="MyInformation.FirstName"></span>

        <label asp-for="MyInformation.LastName">Last Name:* </label>
        <input @(Model.EditMode ? "" : "disabled") asp-for="MyInformation.LastName" value="@Model.MyInformation.LastName" class="form-control ">
        <span asp-validation-for="MyInformation.LastName"></span>

        <label asp-for="MyInformation.PhoneNumber">Phone:* </label>
        <input @(Model.EditMode ? "" : "disabled") id="phone" asp-for="MyInformation.PhoneNumber" value="@Model.MyInformation.PhoneNumber" class="form-control ">
        <span asp-validation-for="MyInformation.PhoneNumber"></span>

        <label asp-for="MyInformation.PhoneExt">Phone Ext: </label>
        <input @(Model.EditMode ? "" : "disabled") asp-for="MyInformation.PhoneExt" value="@Model.MyInformation.PhoneExt" class="form-control">


        <div class="btnGroup @(Model.EditMode ? "visiblyHidden" : "")">
            <input asp-page-handler="Edit" formnovalidate type="submit" name="btnUpdate" value="Edit" id="btnUpdate" title="Edit">
        </div>
        <div class="btnGroup @(Model.EditMode ? "" : "visiblyHidden")">
            <input asp-page-handler="Save" type="submit" name="btnSave" value="Save" id="btnSave" title="Save">
            <input asp-page-handler="Cancel" type="submit" name="btnCancel" value="Cancel" id="btnCancel" title="Cancel">
        </div>
    </form>
</div>

后端代码
[BindProperties]
public class MyInformationModel : PageModel
{
protected ILogger<MyInformationModel> _logger;
private readonly UserManager<T_User> _userManager;
protected ActivityLogger _activityLogger;
protected MyInformationService _myInfomationSettingsService;
public UserViewModel? MyInformation { get; set; }
public bool EditMode { get; set; } = false;


public MyInformationModel(UserManager<T_User> userManager, ILogger<MyInformationModel> logger, ActivityLogger activityLogger, MyInformationService myInformationService)
{
    _logger = logger;
    _activityLogger = activityLogger;
    _userManager = userManager;
    _myInfomationSettingsService = myInformationService;
}

public async Task OnGetAsync()
{
    var user = HttpContext.User;
    var userId = _userManager.GetUserId(user);
    MyInformation = await _myInfomationSettingsService.GetSettingsAsync(userId);
}

public async Task<IActionResult> OnPostSave()
{

    var user = await _userManager.FindByNameAsync(HttpContext?.User?.Identity?.Name?.ToString());
    var userId = await _userManager.GetUserIdAsync(user);


    if (ModelState.IsValid)
    {
        var currentPage = HttpContext?.Request.Path.ToString();
        int startindex = currentPage.LastIndexOf('/') + 1;
        int endindex = currentPage.Length;
        currentPage = currentPage.Substring(startindex, endindex - startindex);

        _logger.LogInformation($"{user} updated user information", DateTime.UtcNow.ToLongTimeString());
        await _activityLogger.Log($"{user} updated user information", currentPage, userId);
        await _myInfomationSettingsService.SetSettingsAsync(MyInformation);


    }
    else
    {
        await _myInfomationSettingsService.GetSettingsAsync(userId);
    }
    return RedirectToPage("/Refunds/MyInformation");
}

public async Task<IActionResult> OnPostCancel()
{
    EditMode = false;
    return RedirectToPage("/Refunds/MyInformation");

}

public async Task OnPostEdit()
{
    EditMode = true;

    var user = await _userManager.FindByNameAsync(HttpContext?.User?.Identity?.Name?.ToString());
    var userId = await _userManager.GetUserIdAsync(user);

    MyInformation = await _myInfomationSettingsService.GetSettingsAsync(userId);
    TryValidateModel(MyInformation.LastName);
    //ModelState.ClearValidationState("MyInformation.FirstName");
    //ModelState.MarkFieldValid("MyInformation.FirstName");
    //ModelState.ClearValidationState("MyInformation.LastName");
    //ModelState.MarkFieldValid("MyInformation.LastName");
    //ModelState.ClearValidationState("MyInformation.PhoneNumber");
    //ModelState.MarkFieldValid("MyInformation.PhoneNumber");

}

修复方案

1. 替换disabled属性,避免验证异常

浏览器会忽略disabled字段的值,导致后端接收不到数据触发验证失败。改用readonly配合CSS模拟禁用效果:

<!-- 示例:修改FirstName字段 -->
<input @readonly="!Model.EditMode" asp-for="MyInformation.FirstName" class="form-control @(!Model.EditMode ? "disabled-style" : "")" />

添加CSS样式:

.disabled-style {
    background-color: #e9ecef;
    cursor: not-allowed;
    border-color: #ced4da;
}

2. 移除手动绑定的value属性

asp-for标签助手已自动处理值绑定,手动添加value会导致重复绑定,引发验证状态混乱:

<!-- 错误写法 -->
<input @(Model.EditMode ? "" : "disabled") asp-for="MyInformation.FirstName" value="@Model.MyInformation.FirstName" class="form-control" />

<!-- 正确写法 -->
<input @readonly="!Model.EditMode" asp-for="MyInformation.FirstName" class="form-control @(!Model.EditMode ? "disabled-style" : "")" />

3. 修复后端Edit动作的验证逻辑

点击编辑后清除旧的验证状态,重新验证模型,并返回当前页面保留编辑状态:

public async Task<IActionResult> OnPostEdit()
{
    EditMode = true;

    var user = await _userManager.FindByNameAsync(HttpContext?.User?.Identity?.Name?.ToString());
    var userId = await _userManager.GetUserIdAsync(user);

    MyInformation = await _myInfomationSettingsService.GetSettingsAsync(userId);
    
    // 清除所有验证状态,重新验证模型
    ModelState.Clear();
    TryValidateModel(MyInformation);

    return Page();
}

4. 修复Save动作的错误处理逻辑

验证失败时保持编辑模式,重新赋值模型并返回当前页面,保留验证错误信息:

public async Task<IActionResult> OnPostSave()
{
    var user = await _userManager.FindByNameAsync(HttpContext?.User?.Identity?.Name?.ToString());
    var userId = await _userManager.GetUserIdAsync(user);

    if (ModelState.IsValid)
    {
        var currentPage = HttpContext?.Request.Path.ToString();
        int startindex = currentPage.LastIndexOf('/') + 1;
        int endindex = currentPage.Length;
        currentPage = currentPage.Substring(startindex, endindex - startindex);

        _logger.LogInformation($"{user} updated user information", DateTime.UtcNow.ToLongTimeString());
        await _activityLogger.Log($"{user} updated user information", currentPage, userId);
        await _myInfomationSettingsService.SetSettingsAsync(MyInformation);

        EditMode = false;
    }
    else
    {
        EditMode = true;
        MyInformation = await _myInfomationSettingsService.GetSettingsAsync(userId);
    }
    return Page();
}

5. 调整Cancel动作返回逻辑

取消时返回当前页面,避免刷新丢失状态:

public IActionResult OnPostCancel()
{
    EditMode = false;
    return Page();
}

内容的提问来源于stack exchange,提问作者L. Wallach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:35:56