C# 如何在页面加载时显示验证错误?
我正在我的应用程序中创建一个功能,用于处理上载的CSV文件,其中包含要导入的多条记录。数据需要验证,我想在单击导入按钮之前显示所有验证错误。高级别计划:C# 如何在页面加载时显示验证错误?,c#,asp.net-mvc,validation,unobtrusive-validation,C#,Asp.net Mvc,Validation,Unobtrusive Validation,我正在我的应用程序中创建一个功能,用于处理上载的CSV文件,其中包含要导入的多条记录。数据需要验证,我想在单击导入按钮之前显示所有验证错误。高级别计划: 步骤1:上传CSV文件 步骤2:显示CSV文件中的所有记录以及每个记录旁边的任何验证错误(缺少必填字段等) 第三步:点击“导入”,实际导入有效记录 以下是我所拥有的内容的简化版本: 用户视图模型 文件上传操作帖子 [HttpPost] [ValidateAntiForgeryToken] 公共操作结果上载(HttpPostedFileBas
- 步骤1:上传CSV文件
- 步骤2:显示CSV文件中的所有记录以及每个记录旁边的任何验证错误(缺少必填字段等)
- 第三步:点击“导入”,实际导入有效记录
[HttpPost]
[ValidateAntiForgeryToken]
公共操作结果上载(HttpPostedFileBase csvFile)
{
//var csvRecords=do stuff从CSV文件检索数据
var newUsersToCreate=newlist();
foreach(csvRecord中的var csvRecord)
{
newUsersToCreate.Add(新用户视图模型
{
Name=csvRecord.Name,
Email=csvRecord.Email,
电话=csvRecord.Phone
});
}
返回视图(“ImportPreview”,newUsersToCreate);
}
查看ImportPreview.cshtml
@model IEnumerable
@使用(Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true,“,new{@class=“alert-alert-danger”,role=“alert”})
名称
电子邮件
电话
验证错误
@EditorFor(model=>model)
进口
}
UserViewModel.cshtml的编辑器模板
@model App.ViewModels.UserViewModel
@Html.HiddenFor(model=>model.Name)
@DisplayFor(model=>model.Name)
@Html.HiddenFor(model=>model.Email)
@DisplayFor(model=>model.Email)
@Html.HiddenFor(model=>model.Phone)
@DisplayFor(model=>model.Phone)
@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”})
问题
虽然这会生成一个很好的“预览”表,其中所有准备好的User
记录基本上都是隐藏字段的行,但问题是,在单击Import按钮之前,它不会显示验证错误
如何让它在返回视图('ImportPreview',newUsersToCreate)返回视图后立即在每行显示每个字段的验证错误?您可以通过检查
$.validator
是否有效在视图中执行此操作。由于默认情况下不会验证隐藏的输入,因此还需要覆盖验证器。在jquery-{version}.js
、jquery.validate.js
和jquery.validate.unobtrusive.js
脚本之后添加以下内容(但不在$(document.ready()
中)
缺点是需要包含jQuery脚本,否则就不需要这些脚本
另一个选项是在控制器中对集合中的每个项目使用TryValidateObject
进行验证,并将所有错误添加到ModelState
,这些错误将显示在ValidationMessageFor()
占位符中。注意:以下假设csvRecords
实现了IList
,因此您可以使用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;
}
[HttpPost]
[ValidateAntiForgeryToken]
公共操作结果上载(HttpPostedFileBase csvFile)
{
//var csvRecords=do stuff从CSV文件检索数据
var newUsersToCreate=newlist();
对于(int i=0;i
控制器代码的优点是,您可以向视图模型中添加一个附加属性(例如
bool IsValid
),并将其用于表行的条件样式设置,并且您可以确定如果存在“太多”错误,您可以只显示一个不同的视图,而不是呈现整个表并显示可能数百条重复的错误消息一个选项是在加载页面时添加一个脚本来验证表单-$('form')。valid()
您还可以使用TryValidateModel(newUsersToCreate);在填充控制器以添加
modelstatererrors`(未测试)后,我已经尝试了这两种方法,但没有成功。不确定是否与这些隐藏字段有关。抱歉,我没有注意到。默认情况下,隐藏的输入不会在视图中验证,但您可以覆盖该输入,请参见示例。但由于它们是隐藏的,用户无法编辑它们,因此不确定显示错误会有什么帮助这正是我所需要的。我选择了第二种方法,因为在我的用例中,在控制器中处理验证并将预验证的模型交付给视图似乎更好。谢谢
[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>
<script>
// override validator to include hidden inputs
$.validator.setDefaults({
ignore: []
});
// validate form and display errors
$('form').valid();
</script>
if ($('form').valid()) {
$('#error').show();
}
[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;
}