【问题标题】:.NET Core 2.2: Validate [required] properties only when object is not null.NET Core 2.2:仅在对象不为空时验证 [必需] 属性
【发布时间】:2019-09-02 05:45:17
【问题描述】:

我有一个包含嵌套对象的复杂模型。我只希望我的[Required] 属性在它们所在的对象不是null 时得到验证。因此,例如,如果我有一个带有Address 属性的Home 类,那么如果Address 不是null,则Home.Address.Street 属性应该是[required]

代码

在 ASP.NET Core 中,我有一个如下所示的模型:

public class Home
{
    [Required]
    public int Number {get;set;}
    public Address Address {get;set;} // This is not required
}
public class Address
{
   [Required]
   public string Street {get;set;}
   public IFormFile Picture {get;set;}

}

在控制器中,我有一个如下所示的操作方法:

[HttpPost]
public string AddHomes([FromForm]List<Home> homes) 
{
    if(!ModelState.IsValid)
    {
        return BadRequest();
    }
    // Do some saving
    return Ok();  
}

表单有效负载如下所示:

homes.Index: 0
homes[0].number: 1

在 ASP.NET Core 2.2 中,homes 列表中的第一个 Home 被标记为无效,但它在 ASP.NET Core 2.1 中可以正常工作。

我想要的是仅在 Address 不是 null 时验证 [Required] 属性。所以Home 可以或者拥有AddressStreet 或者根本没有Address

这在 .NET Core 2.2 中可以实现吗?


注意:我在下面包含了一个更新的示例来重现错误。 似乎包含 IFormFile 会导致 Address 类初始化自身。

{
    "errors": {
        "homes[0].Address.Street": [
            "The Street field is required."
        ]
    },
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "80000009-0003-ff00-b63f-84710c7967bb"
}

我前段时间也在 GitHub 上开了一个 issue,如果有人想跟进:Inclusion of IFormFile property forces the whole object to be validated. ASP.NET Core 2.2

【问题讨论】:

  • 为什么不从 Street 中删除 [Required] ??
  • 那么它会将对象解析为不为空,并且会有一个名称为空的地址。这也是一个简化的例子。我想知道如何解决问题而不是更改预期的功能。
  • @Nejdi 我无法重现您的问题,ASP.NET Core 2.2 给了我ModelState.IsValid == true,您是否查看了ModelState.Values 并查看哪个字段无效?
  • 你好@Never我更新了这个例子来重现我的错误。似乎是在子模型中包含 IFormFile 导致它自己初始化。我还在更新的响应中包含了 BadRequestError
  • 您将IFormFile 发布到正确的位置了吗?即IFormFile 应该发布到Home[1].Address.Picture。显然,发帖到Home[0].Address.Picture 会触发验证错误。

标签: c# validation asp.net-core asp.net-core-webapi model-binding


【解决方案1】:

你想要的行为空引用属性的行为,它在 ASP.NET Core 2.2 中没有改变。仅当引用本身为非空时,才验证被引用类的属性。如果这对您不起作用,那么唯一的结论是此引用属性确实 具有值。它可能只是一个默认实例化(即new Foo()),实际上没有定义任何子属性,但这足以触发验证。

首先,确保您没有为属性设置默认值,或者通过构造函数为其提供默认值。换句话说,如果你有类似的东西:

public Bar Bar { get; set; } = new Bar();

或者,

public Foo()
{
    Bar = new Bar();
}

删除它。

此外,请注意,如果为该引用属性发布了 任何内容,那么一切都会发挥作用。即使您只有一些隐藏的属性,例如:

<input type="hidden" asp-for="Bar.Id" />

如果引用上的任何一个属性被发布,即使它本身是无效的,该类的所有验证都会发挥作用。

【讨论】:

  • 您好@Chris Pratt,我更新了示例以重现我的错误。似乎是在子模型中包含 IFormFile 导致它自己初始化。可以看看吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 2019-11-02
  • 1970-01-01
  • 1970-01-01
  • 2021-05-05
  • 2020-10-10
  • 1970-01-01
相关资源
最近更新 更多