在 ASP.NET 核心模型绑定中使用 Required 和 JsonRequired 与 JSON body

Using Required and JsonRequired in ASP.NET Core Model Binding with JSON body

我正在使用 ASP.NET Core 2.0,我有一个请求 object 注释如下:

public class MyRequest
{
    [Required]
    public Guid Id { get; set; }

    [Required]
    public DateTime EndDateTimeUtc { get; set; }

    [Required]
    public DateTime StartDateTimeUtc { get; set; }
}

在我的控制器中:

public async Task<IActionResult> HandleRequest([FromBody] MyRequest request)
{ /* ... */ }

我注意到模型绑定的一个问题:当我发送一个包含设置为 application/json 的 header Content-Type 和一个空的 body 的请求时,如我所料,我控制器中的 requestnullModelState.IsValidfalse.

但是当我有这样的 body 时:

{
  "hello": "a-string-value!"
}

我的 request 不是 null,它有所有的默认值,ModelState.IsValidtrue

这当然是在我缺少所有 Required 属性时发生的,并且唯一存在的名字与那里的 属性 不匹配(甚至这个单个参数的类型是string,与我的模型上的任何类型都不匹配。

所以在某种程度上,如果我的请求中没有任何内容,那些 Required 属性似乎可以工作,但如果我的请求不为空,它们就不会执行任何操作!

当我准备这个问题时,我注意到还有一个 JsonRequired 属性,它似乎处理了存在的属性。

那么,RequiredJsonRequired 有什么区别?

为了 Required 属性的正确工作,您应该使属性可为空:

public class MyRequest
{
    [Required]
    public Guid? Id { get; set; }

    [Required]
    public DateTime? EndDateTimeUtc { get; set; }

    [Required]
    public DateTime? StartDateTimeUtc { get; set; }
}

现在,如果您发送缺少 IdEndDateTimeUtcStartDateTimeUtc 的请求,相应的字段将设置为 null,将设置为 ModelState.IsValid falseModelState 将包含错误描述,例如The EndDateTimeUtc field is required.

JsonRequired 属性特定于 JSON.Net。它在反序列化期间播放,而 Required 属性(与 System.ComponentModel.DataAnnotations 命名空间中的其他属性一样)在模型反序列化之后,在模型验证期间播放。如果 JsonRequired 属性被违反,模型将不会被反序列化,相应的动作参数将被设置为 null.

您应该更喜欢 Required 属性而不是 JsonRequired 的主要原因是 JsonRequired 不适用于其他内容类型(如 XML)。 Required 反过来是通用的,因为它是在模型反序列化后应用的。

当您使用 [FromBody] 作为绑定源时,模型属性将获得默认值并且 [BindRequired] 将被忽略。 "Problems with Parameter Validation".

上有一个相关问题

在这种情况下,最好使用 [JsonRequired] 而不是 [BindRequired] 来强制执行绑定属性。

注意 [JsonRequired] 影响序列化和反序列化。

是的,困难在于,如果您选择 Required,Web 请求客户端的语义会发生错误更改 - 即您说您可以传入一个空值,而实际上您确实需要一个正确的值。

使用 JsonRequired 对此进行排序,但这是由 NewtonSoft 提供的,因此当您升级到 .Net Core 3 时停止工作。这是因为 .Net Core 3 使用自己的 Json 解析器而不是 NewtonSoft。