根据需要验证正文中的不可为空属性 - AspNetCore 3.1

Oli*_*ver 5 c# asp.net-mvc .net-core asp.net-core asp.net-core-3.1

我试图验证是否在 ModelState 无效的请求中完全忽略了属性/字段,并且 BadRequest 被发送回客户端,但是我正在努力处理请求正文中的不可为空类型。

适用于可为空类型

[Required] public string NullableString { get; set; }
Run Code Online (Sandbox Code Playgroud)

适用于不可为空和可为空的参数

public IActionResult RequiredNonNullableIntQueryString([Required]int nonNullableInt)

public IActionResult RequiredNullableStringQueryString([Required]string nullableString)
Run Code Online (Sandbox Code Playgroud)

但是,它不适用于请求正文中的不可为空类型

 public IActionResult RequiredNonNullableIntBody([FromBody]NonNullablesRequest request)

 public class NonNullablesRequest
 {
    [Required] // I have also tried [BindRequired] with the same result.
    public int NonNullableInt { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

我读过了:

Microsoft 文档指出:

.NET Core 3.0 及更高版本中的验证系统将不可为 null 的参数或绑定属性视为具有 [Required] 特性。值类型(例如 decimal 和 int)是不可为空的。

那很酷……不过后来说

在服务器上,如果属性为空,则认为缺少必需的值。不可为空的字段始终有效,并且永远不会显示 [Required] 属性的错误消息。

为什么?这似乎真的没有意义。为什么要确保所有非空值都是必需的,但如果未提供它们,则忽略错误?

我知道许多建议表明可以执行以下操作,即可以将所需参数设置为可空。对我来说,这似乎不是一个合理的解决方案。

 public class NonNullablesRequest
 {
    [Required]
    public int? NonNullableInt { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

这只是感觉不对。

  • 数据类型不能准确表示请求到达的期望
  • 必须在每次访问该属性时使用.HasValue.Value以避免“可能为空”警告。
  • 似乎是 C# 8.0 的Nullable 引用类型的反模式(C# 参考)

如果未提供不可为空的类型,有没有办法配置 ModelBinding 以使 ModelState 无效?

编辑1:

似乎有一些争论:ASP.NET Core [Require] non-nullable types 我不确定我是否同意 Chris Pratt。并不是我们期望不提供价值。事实上恰恰相反,我想确保调用者给我值。但是我们必须对没有提供足够数据的消费者采取防御措施,因此系统应该以 400 BadRequest 拒绝请求。

由此看来,预期的结果是一个intnot an int?。如果未提供任何数据,则 ModelBinder 应指示 ModelState 无效。

但是,我可以看到有两个部分的挑战:1)反序列化,然后是 2)ModelBinding。

Mik*_*J82 3

您可以为此使用两个不同的类。

一个代表您的 Web 应用程序发送到后端的内容,另一个代表您的域模型(例如实体模型)。

HTTP 传输对象

 public class YourWebAppDto
 {
    [Required]
    public int? NonNullableInt { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

领域模型对象

 public class YourDomainModelObject
 {
    public int NonNullableInt { get; set; }
 }
Run Code Online (Sandbox Code Playgroud)

通过分离这两个问题,您可以保持域模型干净,同时解决 Web 应用程序的潜在无效输入。

当然,您需要两者之间的映射。我们为此使用自动映射器。

我知道,这并不能直接回答您的问题,但作为看待事物的另一种方式可能会有所帮助。

干杯,迈克

  • 感谢@MikeJ82,验证主要是在传输对象上,在内部,请求和响应对象不会比控制器操作更进一步。1. 仍然感觉很混乱,必须不准确地描述数据类型 2. 意味着类的重复和自动映射器的性能损失 (3认同)