Asp.net Core 2 MVC只读场景下EF模型验证错误展示问题咨询
首先得明确:从数据库直接读取模型实例时,默认不会自动触发验证规则,也不会把验证错误添加到模型的状态里。ASP.NET Core的模型验证默认是在模型绑定(比如表单提交、API接收数据)时触发的,而从数据库查询出来的实体只是普通的CLR对象,不会自动执行验证逻辑。
下面逐个解答你的问题:
1. 从数据库获取模型时,验证消息是否会添加到模型中?
不会的。默认情况下,EF Core(或你使用的其他ORM)只是把数据库数据映射到实体类属性上,不会触发数据注解的验证逻辑。你需要手动对每个从数据库获取的Employee实例进行验证,再把验证错误存储起来,才能在视图里使用。
你可以在控制器里这么做:
var employees = _context.Employees.ToList(); var employeeValidationErrors = new Dictionary<Employee, List<ValidationResult>>(); foreach (var emp in employees) { var validationResults = new List<ValidationResult>(); var validationContext = new ValidationContext(emp, null, null); bool isValid = Validator.TryValidateObject(emp, validationContext, validationResults, validateAllProperties: true); if (!isValid) { employeeValidationErrors.Add(emp, validationResults); } } // 将错误字典传递到视图 ViewData["ValidationErrors"] = employeeValidationErrors; return View(employees);
2. 能否在Razor视图中访问验证错误?
当然可以。只要把验证错误信息传到视图,就能在Razor里遍历展示。
比如在Index.cshtml里可以这样实现:
@model IEnumerable<Employee> @{ var validationErrors = ViewData["ValidationErrors"] as Dictionary<Employee, List<ValidationResult>>; } <table class="table"> <thead> <tr> <th>ID</th> <th>First Name</th> <th>Last Name</th> <th>Email</th> <th>Status</th> </tr> </thead> <tbody> @foreach (var emp in Model) { <tr> <td>@emp.ID</td> <td>@emp.FirstName</td> <td>@emp.LastName</td> <td>@emp.EmailAddress</td> <td> @if (validationErrors != null && validationErrors.ContainsKey(emp)) { <!-- 警告图标,以Bootstrap为例 --> <button type="button" class="btn btn-link p-0" data-toggle="modal" data-target="#errorModal-@emp.ID"> <i class="fas fa-exclamation-triangle text-warning"></i> </button> <!-- 模态框展示错误详情 --> <div class="modal fade" id="errorModal-@emp.ID" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Validation Errors for @emp.FirstName @emp.LastName</h5> <button type="button" class="close" data-dismiss="modal"> <span>×</span> </button> </div> <div class="modal-body"> <ul> @foreach (var error in validationErrors[emp]) { <li>@error.ErrorMessage</li> } </ul> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> } </td> </tr> } </tbody> </table>
这样就能在有验证错误的员工行显示警告图标,点击后弹出模态框查看所有错误信息。
3. 若使用ViewModel,能否通过AutoMapper将验证规则从模型转移到ViewModel?
AutoMapper本身不会自动复制数据注解(包括验证规则)到ViewModel上,但有两种方案可以实现类似效果:
方案一:手动在ViewModel上重复添加验证注解
这是最直接可靠的方式,比如创建EmployeeViewModel并复制实体类的验证注解:
public class EmployeeViewModel { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } [DataType(DataType.EmailAddress)] [Required(ErrorMessage = "An Email Address is required")] public string EmailAddress { get; set; } }
之后用AutoMapper把Employee映射到EmployeeViewModel,再对ViewModel实例执行和之前一样的验证逻辑即可。
方案二:使用第三方扩展库复制注解
有一些第三方库(比如AutoMapper.DataAnnotations)可以帮助自动复制实体类的数据注解到ViewModel,但要注意版本兼容性(你使用的是ASP.NET Core 2,需要找对应版本的包)。不过这种方式可能存在复杂注解无法完全复制的问题,所以手动添加还是更稳妥的选择。
不管用实体类还是ViewModel,核心逻辑都是手动触发验证、收集错误、传递到视图展示,因为数据库查询不会自动触发验证流程。
内容的提问来源于stack exchange,提问作者craig

