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

.NET Core 6动态表单添加前后端验证方案咨询

动态表单的前后端必填验证实现(.NET Core 6)

问题背景

我在.NET Core 6 Web应用中有一个基于项数组动态生成输入字段的表单,每个项定义了字段类型、数据类型以及是否为必填项。目前表单生成逻辑正常,但需要给必填项(IsMandatory=true)添加客户端+服务端验证,且要能通过ModelState.IsValid校验。由于字段是动态的,无法用常规ViewModel特性标记。当前已引入aspnet-validation.js,想确认是否还需额外JS实现客户端验证。

现有代码

CSHTML代码(精简版)

@using Microsoft.AspNetCore.Mvc.TagHelpers
@inherits UmbracoViewPage<AdditionalInfoViewModel>

<fieldset class="panel--shadow">
    <div class="panel theme--white">
        @for (var i = 0; i < Model.AdditionalInfo.Count; i++)
        {
            var item = Model.AdditionalInfo[i];
            var required = item.IsMandatory ? "required" : "";
            var fieldId = item.UdfName.Replace(' ', '-');

            <div class="form-group mb-4 @required">
                <input asp-for="@Model.AdditionalInfo[i].UdfName" type="hidden" />

                @{
                    var fieldName = Model.AdditionalInfo[i].TitleOverride;

                    switch (Model.AdditionalInfo[i].UdfDataType)
                    {
                        case "Text":
                            <label for="@fieldId" class="form-label mb-2">@fieldName</label>
                            <input class="form-control" id="@fieldId" asp-for="@Model.AdditionalInfo[i].UdfValue" type="text"/>
                            break;

                        default:
                            <label for="@fieldId" class="form-label mb-2">@fieldName</label>
                            <input class="form-control d-inline-block w-auto" id="@fieldId" asp-for="@Model.AdditionalInfo[i].UdfValue" type="text"/>
                            break;
                    }

                    if (Model.AdditionalInfo[i].IsMandatory)
                    {
                        <span class="field-validation-valid" data-valmsg-for="@fieldId" data-valmsg-replace="true"></span>
                    }
                }
            </div>
        }
    </div>

    <div class="panel theme--river text-center">
        <button class="btn btn-theme btn-primary js-additionalinfo-continue"
                type="@Html.If(Model.HasNextStep, "button", "submit")">
            @if (!Model.HasNextStep)
            {
                <i class="far fa-shopping-basket" aria-hidden="true"></i>
            }
            @Html.If(Model.HasNextStep, "Continue", "Add to basket")
            <i class="fa-regular fa-arrow-right" aria-hidden="true"></i>
        </button>
    </div>
</fieldset>

ViewModel定义

public class AdditionalInfoViewModel
{
    public AdditionalInfoViewModel()
    {
        Notice = string.Empty;
        AdditionalInfo = new List<AdditionalInfoListItem>();
    }

    public string Notice { get; set; }
    public bool HasNextStep { get; set; }

    public List<AdditionalInfoListItem>? AdditionalInfo { get; set; }
}

AdditionalInfoListItem定义

public class AdditionalInfoListItem
{
    public string UdfName { get; set; }
    public string? TitleOverride { get; set; }
    public bool IsMandatory { get; set; }
    public string? UdfDataType { get; set;}
    public List<ListValueItem>? ListValues { get; set; }
    public string? UdfValue { get; set; }
}

public class ListValueItem
{
    public string ListValueName { get; set; }
    public bool Selected { get; set; }
}

解决方案

一、服务端验证实现

由于字段是动态生成的,无法使用DataAnnotation特性,需在Action中手动校验必填项:

[HttpPost]
public IActionResult Submit(AdditionalInfoViewModel model)
{
    if (model.AdditionalInfo != null)
    {
        foreach (var (item, index) in model.AdditionalInfo.Select((item, idx) => (item, idx)))
        {
            if (item.IsMandatory && string.IsNullOrWhiteSpace(item.UdfValue))
            {
                // 生成与前端name属性一致的字段名,确保错误信息关联到对应输入框
                var fieldName = $"AdditionalInfo[{index}].UdfValue";
                var displayName = item.TitleOverride ?? item.UdfName;
                ModelState.AddModelError(fieldName, $"{displayName} 为必填项");
            }
        }
    }

    if (!ModelState.IsValid)
    {
        // 返回原视图并显示验证错误
        return View(model);
    }

    // 后续业务逻辑处理
    return RedirectToAction("Success");
}

二、客户端验证实现

你已引入aspnet-validation.js,无需额外JS库,但需修改CSHTML代码生成正确的验证标记:

修改后的CSHTML核心代码

@for (var i = 0; i < Model.AdditionalInfo.Count; i++)
{
    var item = Model.AdditionalInfo[i];
    var required = item.IsMandatory ? "required" : "";
    var fieldId = item.UdfName.Replace(' ', '-');
    var displayName = item.TitleOverride ?? item.UdfName;

    <div class="form-group mb-4 @required">
        <input asp-for="@Model.AdditionalInfo[i].UdfName" type="hidden" />

        @{
            switch (Model.AdditionalInfo[i].UdfDataType)
            {
                case "Text":
                    <label for="@fieldId" class="form-label mb-2">
                        @displayName @(item.IsMandatory ? "<span class='text-danger'>*</span>" : "")
                    </label>
                    <input class="form-control" id="@fieldId" 
                           asp-for="@Model.AdditionalInfo[i].UdfValue" 
                           type="text"
                           @(item.IsMandatory ? $"data-val='true' data-val-required='{displayName} 为必填项'" : "")/>
                    break;

                default:
                    <label for="@fieldId" class="form-label mb-2">
                        @displayName @(item.IsMandatory ? "<span class='text-danger'>*</span>" : "")
                    </label>
                    <input class="form-control d-inline-block w-auto" id="@fieldId" 
                           asp-for="@Model.AdditionalInfo[i].UdfValue" 
                           type="text"
                           @(item.IsMandatory ? $"data-val='true' data-val-required='{displayName} 为必填项'" : "")/>
                    break;
            }

            // 使用asp-validation-for自动关联验证提示,替代手动写的span
            if (item.IsMandatory)
            {
                <span asp-validation-for="@Model.AdditionalInfo[i].UdfValue" class="text-danger"></span>
            }
        }
    </div>
}

关键调整点

  1. 给必填项手动添加data-val="true"和data-val-required属性,这是ASP.NET Core客户端验证的识别标记。
  2. 用asp-validation-for标签助手替代手动编写的验证提示容器,它会自动生成与输入框name匹配的data-valmsg-for属性,确保错误信息正确显示。
  3. 给必填项标签添加红色星号,增强用户体验。

验证初始化(可选)

如果布局页未引入_ValidationScriptsPartial.cshtml,需手动初始化验证:

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const forms = document.getElementsByTagName('form');
        Array.from(forms).forEach(form => aspnetValidation.validate(form));
    });
</script>

验证效果

  • 服务端:提交后Action的手动校验会将错误加入ModelState,ModelState.IsValid返回false,错误信息自动回显到对应输入框下方。
  • 客户端:aspnet-validation.js会在表单提交前检查必填项,阻止非法提交并显示错误提示,无需额外自定义JS。

内容的提问来源于stack exchange,提问作者GordonS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 22:02:07