如何在页面加载时显示验证错误?

时间:2017-09-10 04:26:02

标签: c# asp.net-mvc validation unobtrusive-validation

我正在我的应用中创建一个功能来处理上传的CSV文件,其中包含要导入的多个记录。数据需要验证,我想在单击导入按钮之前显示任何验证错误。高级计划:

  • 第1步:上传CSV文件
  • 步骤2:显示CSV文件中的所有记录以及每条记录旁边的任何验证错误(缺少必填字段等)
  • 步骤3:点击“导入”以实际导入有效记录。

以下是我所拥有的简化版本:

用户视图模型

public class UserViewModel
{
    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    [Required]
    [StringLength(150)]
    public string Email { get; set; }

    [Required]
    [StringLength(10)]
    public string Phone { get; set; }
}

文件上传操作帖子

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
    // var csvRecords = do stuff to retrieve data from CSV file
    var newUsersToCreate = new List<UserViewModel>();

    foreach (var csvRecord in csvRecords)
    {
        newUsersToCreate.Add(new UserViewModel
        {
            Name = csvRecord.Name,
            Email = csvRecord.Email,
            Phone = csvRecord.Phone
        });
    }
    return View("ImportPreview", newUsersToCreate);
}

查看ImportPreview.cshtml

@model IEnumerable<App.ViewModels.UserViewModel>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true, "", new { @class = "alert alert-danger", role = "alert" })

    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Email</th>
                <th>Phone</th>
                <th>Validation Errors</th>
            </tr>
        </thead>
        <tbody>
            @Html.EditorFor(model => model)
        </tbody>
    </table>

    <button type="submit">Import</button>
}

UserViewModel.cshtml的编辑器模板

@model App.ViewModels.UserViewModel

<tr>
    <td>
        @Html.HiddenFor(model => model.Name)
        @Html.DisplayFor(model => model.Name)
    </td>
    <td>
        @Html.HiddenFor(model => model.Email)
        @Html.DisplayFor(model => model.Email)
    </td>
    <td>
        @Html.HiddenFor(model => model.Phone)
        @Html.DisplayFor(model => model.Phone)
    </td>
    <td>
        @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
        @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
        @Html.ValidationMessageFor(model => model.Phone, "", new { @class = "text-danger" })
    </td>
</tr>

问题

虽然这会生成一个漂亮的“预览”表,其中所有准备好的User记录基本上都是隐藏字段的行,但问题是它在导入按钮。

如何在return View('ImportPreview', newUsersToCreate)返回视图后立即显示每行中的每个字段验证错误?

1 个答案:

答案 0 :(得分:2)

您可以通过检查$.validator是否有效来在视图中执行此操作。由于默认情况下未验证隐藏的输入,因此您还需要覆盖验证器。在jquery-{version}.jsjquery.validate.jsjquery.validate.unobtrusive.js脚本之后添加以下内容(但不在$(document).ready()中)

<script>
    // override validator to include hidden inputs
    $.validator.setDefaults({ 
        ignore: [] 
    });
    // validate form and display errors
    $('form').valid();
</script>

请注意,您可以添加一个(例如)<p id="error" style="display:none;">标记,其中包含&#39; general&#39;数据无效的错误消息并使用

if ($('form').valid()) {
    $('#error').show();
}

缺点是你需要包含不需要的jQuery脚本。

另一个选项是在控制器中使用TryValidateObject在集合中的每个项目上进行验证,并将任何错误添加到ModelState,这些错误将显示在ValidationMessageFor()占位符中。请注意,以下假设csvRecords实现IList<T>,以便您可以使用for循环。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
    // var csvRecords = do stuff to retrieve data from CSV file
    var newUsersToCreate = new List<UserViewModel>();
    for (int i = 0; i < csvRecords.Count; i++)
    {
        UserViewModel model = new UserViewModel
        {
            Name = csvRecords[i].Name,
            ....
        };
        newUsersToCreate.Add(model);
        // validate the model and include the collection indexer
        bool isValid = ValidateModel(model, i));   
    }
    return View("ImportPreview", newUsersToCreate);
}

private bool ValidateModel(object model, int index) 
{ 
    var validationResults = new List<ValidationResult>(); 
    var context = new ValidationContext(model); 
    if (!Validator.TryValidateObject(model, context, validationResults, true)) 
    { 
        foreach (var error in validationResults) 
        { 
            string propertyName = $"[{index}].{error.MemberNames.First()}"; 
            ModelState.AddModelError(propertyName, error.ErrorMessage); 
        } 
        return false; 
    } 
    return true; 
}

控制器代码的优点是您可以向视图模型添加其他属性(例如bool IsValid)并将其用于表行的条件样式,并且您可以决定是否存在& #39;太多&#39;错误,您可以只显示一个不同的视图,而不是呈现整个表并显示可能数百个重复的错误消息