属性为
[Required]
且可为 null 意味着什么? (下面的例子)看来,如果是[Required]
,就不可能是null
(无值),如果能够是null
,那也不可能是[Required]
。
[Required]
public DateTime? OrderDate { get; set; }
将属性设为可为空并标记为
[Required]
属性的原因是为了防止低发布攻击。它还允许您在视图中显示初始空值而不是属性的默认值。这通常是通过视图模型中的值类型属性来完成的。
发布不足攻击是指恶意用户修改请求以省略请求中属性的值。如果属性为
DateTime
(不可为空),则 DefaultModelBinder
将初始化其默认值 (01/01/0001
),并且不会生成 ModelState
错误。因此,该值可能会被保存,即使它不是您所期望的。
如果该属性为
DateTime?
(可空)且 [Required]
,那么如果恶意用户确实在请求中省略了该属性,则会生成 ModelState
错误,因为请求中需要一个值,而视图将被返回,因此无效数据将不会被保存。
另请参阅 Brad Wilson 的文章 ASP.NET MVC 中的输入验证与模型验证以及标题为 “发布不足”问题的部分。
它可以为空,因此表单不会显示像
0001-01-01T00:00:00
这样没有意义的初始值。
需要强制用户输入一些内容。
required
用于客户端验证,nullable
用于数据库映射
必需的是视图的数据注释。该视图将要求它在接受表单帖子之前具有一个值。
该值可以为空与数据库中允许的值有关。数据库中的值可能为 null,或者该值可能会保留为 null。
它们是不同的方面。
在检查项目中的问题时,遇到了规则 csharpsquid:S6964:
在控制器操作中用作输入的值类型属性应该可以为空、必需或使用 JsonRequiredAttribute 进行注释,以避免发布不足。
为什么将可空类型与[必需]一起使用?
[Required] 属性旨在确保客户端在发出请求时显式提供值。然而,在某些情况下,它本身并不能有效地发挥作用,尤其是对于不可为空值类型。
原因如下:
默认值分配
当客户端省略不可为 null 的值类型属性(例如 int、decimal、bool)时,模型绑定器不能将其保留为未设置。相反,它分配类型的默认值:
整数 → 0 布尔→假 小数 → 0.0 这种自动分配可能会导致意外行为(称为发布不足),因为默认值可能不代表来自客户端的有效输入。
可空类型作为解决方案
通过将属性声明为可为空(例如,int?、bool?、decimal?),您可以创建一个值可以显式为空的状态。 当与 [Required] 属性结合使用时,模型绑定器强制客户端必须提供有效值或将其显式设置为 null。这可确保该属性永远不会无意中设置为其默认值。
我的想法
虽然这种方法解决了问题,但实现它需要在整个代码库中添加大量空检查,这可能会增加复杂性和维护开销。
因此,我选择在该项目的 SonarQube 中禁用此规则。