本文讨论 ASP.NET Core 2.1 中与 ASP.NET Core MVC / web API 控制器中的模型绑定相关的功能虽说这是一个功能, 但从我的角度来看, 它更像是一个错误修复!
请注意, 我使用的是 NET Core 2.1 Preview 1, 正式版发布后, 功能可能存在变动
ASP.NET Core 2.0 模型验证
模型验证是 ASP.NET Core MVC 管线的重要组成部分有很多方法可以注入到验证层(例如使用 FluentValidation https://github.com/JeremySkinner/FluentValidation/wiki/i.-ASP.NET-Core-integration), 最常见的方法可能是使用来自
System.ComponentModel
的验证标记来修饰绑定模型 https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation 例如:
- public class UserModel
- {
- [Required, EmailAddress]
- public string Email { get; set; }
- [Required, StringLength(1000)]
- public string Name { get; set; }
- }
如果您在控制器的操作方法中使用 UserModel,MvcMiddleware 则会自动创建对象的新实例, 绑定模型的属性并使用如下三个来源对其进行验证:
表单 - 当使用 POST 将表单发送到服务器时, 发送到 HTTP 请求的主体中;
路由 - 在匹配路由后从 URL 段或默认值中获取;
查询字符串 - 在 URL 的末尾传递
请注意, 目前, 作为 JSON 发送的数据默认情况下不会被绑定如果您希望绑定请求体中的 JSON 数据, 则需要使用此处所述 https://andrewlock.net/model-binding-json-posts-in-asp-net-core/ 的[FromBody]标记修饰模型
在控制器 Action 方法中, 可以简单地检查 ModelState 属性, 确定提供的数据是否有效:
- public class CheckoutController : Controller
- {
- public IActionResult SaveUser(UserModel model)
- {
- if(!ModelState.IsValid)
- {
- // Something wasn't valid on the model
- return View(model);
- }
- // The model passed validation, do something with it
- }
- }
这是非常标准的 MVC 内容, 但是如果您不想创建整个绑定模型, 但仍想验证传入数据, 该怎么办?
ASP.NET Core 2.0 顶级参数
DataAnnotation 标记默认 MVC 验证系统使用的属性不必应用于类的属性, 它们也可以应用于参数这可能会导致您认为您可以完全替换 UserModel 上面的示例中的以下内容:
MVC 默认验证系统使用的 DataAnnotation 标记不一定应用于类的属性, 它们同样可以应用于参数这可能会导致您认为可以完全替换上面示例中的 UserModel, 如下所示:
- public class CheckoutController : Controller
- {
- public IActionResult SaveUser(
- [Required, EmailAddress] string Email
- [Required, StringLength(1000)] string Name)
- {
- if(!ModelState.IsValid)
- {
- // Something wasn't valid on the model
- return View(model);
- }
- // The model passed validation, do something with it
- }
- }
不幸的是, 这是行不通的! 在绑定属性时, 验证属性将被忽略, 并且 ModelState.IsValid 始终是 true!
ASP.NET Core 2.1 中的顶级参数
幸运的是, ASP.NET Core 团队意识到了这个问题 https://github.com/aspnet/Mvc/issues/6825, 并且已经将修补程序合并为 ASP.NET Core 2.1 的一部分 https://github.com/aspnet/Mvc/issues/6790 因此, 上一节中的代码的行为与您所期望的一样, 参数经过验证, 并相应地进行了 ModelState.IsValid 更新
作为这项工作的一部分, 您现在还可以使用 [BindRequired] 标记修饰参数当绑定非空值类型时, 此标记很重要, 因为使用 [Required] 标记对这些属性并不能提供预期的行为
这意味着您现在可以执行以下操作, 并确保 testId 参数已从路由参数中正确绑定, 并且 qty 参数已从查询字符串中绑定在 ASP.NET Core 2.1 之前, 它甚至不能编译!
- [HttpGet("test/{testId}")]
- public IActionResult Get([BindRequired, FromRoute] Guid testId, [BindRequired, FromQuery] int qty)
- {
- if(!ModelState.IsValid)
- {
- return BadRequest(ModelState);
- }
- // Valid and bound
- }
对于这个问题可以查阅我之前的博客: ASP.NET Core MVC 中的 [Required]与[BindRequired]
总结
在 ASP.NET Core 2.0 及以下版本中, 应用于顶级参数的验证标记将被忽略, 并且 ModelState 不会更新只考虑复杂模型类型的验证参数
在 ASP.NET Core 2.1 中, 验证标记现在将在顶级参数上得到遵守更重要的是, 您可以将 [BindReqired] 标记应用于参数
ASP.NET Core 2.1 增加了很多新特性 https://blogs.msdn.microsoft.com/webdev/2018/02/02/asp-net-core-2-1-roadmap/ 这是一些不错的小改进之一, 它使事情变得更容易, 更一致 -- 我喜欢这种改变
翻译自 https://andrewlock.net/coming-in-asp-net-core-2-1-top-level-mvc-parameter-validation/ https://andrewlock.net/coming-in-asp-net-core-2-1-top-level-mvc-parameter-validation/
来源: https://www.cnblogs.com/tdfblog/p/asp-net-core-2-1-top-level-mvc-parameter-validation.html