我正在我的应用中创建一个功能来处理上传的CSV文件,其中包含要导入的多个记录。数据需要验证,我想在单击导入按钮之前显示任何验证错误。高级计划:
以下是我所拥有的简化版本:
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);
}
@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>
}
@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)
返回视图后立即显示每行中的每个字段验证错误?
答案 0 :(得分:2)
您可以通过检查$.validator
是否有效来在视图中执行此操作。由于默认情况下未验证隐藏的输入,因此您还需要覆盖验证器。在jquery-{version}.js
,jquery.validate.js
和jquery.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;错误,您可以只显示一个不同的视图,而不是呈现整个表并显示可能数百个重复的错误消息