Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core 2.2: Validate [required] properties only when object is not null

I have a complex model with nested objects. I only want my [Required] attributes to be validated when the object they are on is not null. So, for example, if I have a Home class with an Address property, the Home.Address.Street property should only be [required] if the Address is not null.

Code

In ASP.NET Core, I have a model that looks like this:

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;}

}

In a controller, I have an action method that looks like this:

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

And the form payload looks like:

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

In ASP.NET Core 2.2, the first Home in the homes list is marked as invalid, but it was working as I would expect in ASP.NET Core 2.1.

What I want is for the [Required] attribute to only be validated if the Address is not null. So a Home can either have an Address with a Street or no Address at all.

Is this achievable in .NET Core 2.2?


Note: I've included an updated example below to reproduce error. It seems that the inclusion of IFormFile causes the Address class to initialize itself.

{
    "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"
}

I also opened an issue on GitHub for this some time ago, if anybody wants to follow up: Inclusion of IFormFile property forces the whole object to be validated. ASP.NET Core 2.2.

like image 496
Nejdi Kroi Avatar asked Apr 11 '19 14:04

Nejdi Kroi


Video Answer


1 Answers

The behavior you're wanting is the behavior for null reference properties, and it has not changed in ASP.NET Core 2.2. The properties on the referenced class are only validated if the reference itself is non-null. If this isn't working for you, then the only conclusion is that this reference property does have a value. It might just be a default instantiation (i.e. new Foo()), with none of the sub properties actually defined, but that is enough to trigger validation.

First, ensure that you are not setting a default value for the property, or otherwise providing it a default through the contructor, for example. In other words, if you have something like:

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

Or,

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

Remove that.

Also, realize that if anything is posted for that reference property, then everything comes into play. Even if you just have some hidden property like:

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

If any one property on the reference is posted, even if it, itself, is not valid, all validation on the class will come into play.

like image 153
Chris Pratt Avatar answered Oct 03 '22 06:10

Chris Pratt