Bastiflew
Bastiflew

Reputation: 1166

BindRequired on DateTime

I have an issue with [BindRequired] attribute, it does not invalidate my model state:

public class PostModel
{
    [BindRequired]
    public DateTime Date { get; set; }
}

Controller:

[ApiController]
public class BindTestController : ControllerBase
{
    [HttpPost("test")]
    public IActionResult SetValue([FromBody] PostModel request)
    {
        if (!ModelState.IsValid)
            return BadRequest();

        return Ok();
    }
}

if I post a body like this:

{}

My modelstate is valid. What is the good way of validating that Date is present on my body, and invalidate the model ?

Thanks

Upvotes: 1

Views: 1474

Answers (3)

Stephen Murumba
Stephen Murumba

Reputation: 549

When to use BindRequired and Required attributes

The BindRequired and Required attributes are often confused because they imply some form of “required-ness” for model properties. However, they serve different purposes and are used in different contexts. It is important to understand when to use them in order to correctly implement data validation and model-binding behavior.

BindRequired Attribute

  • Context: Model Binding
  • Purpose: The BindRequired attribute, from the Microsoft.AspNetCore.Mvc.ModelBinding namespace handles model binding behavior. It is used to indicate that a property must be present in the incoming data for binding to succeed. If the property is not present in the incoming request, the model state becomes invalid.
  • Behavior: Unlike Required, BindRequired does not concern itself with validating the property’s content (whether empty or null) but rather with its presence in the request. This is useful for ensuring that key parts of the model are not omitted in the request.

Example

using Microsoft.AspNetCore.Mvc.ModelBinding;
public class UpdateModel
{
    [BindRequired]
    public int Id { get; set; }  // Must be present in the incoming request
}

Required Attribute

  • Context: Data Annotation for Validation
  • Purpose: The Required attribute is part of the System.ComponentModel.DataAnnotations namespace and is used primarily for model validation. It ensures that a property has a value; it is mainly used to enforce that a field should not be null or empty during model validation.
  • Behavior: When a model is validated (usually after model binding has occurred), if a property marked with the Required attribute does not have a value, the model state is considered invalid. This attribute affects the server-side validation process and is also used to generate client-side validation rules.

Example

using System.ComponentModel.DataAnnotations;
public class RegisterModel
{
    [Required]
    public string Email { get; set; }  // Must have a non-null/non-empty value
}

Use Required Attribute when you need to ensure that a property is not empty or null (common for forms and data entry scenarios). Use BindRequired when you need to ensure that certain data elements are actually present in the incoming request, typically important in APIs and data update scenarios.

Upvotes: 0

Hameed
Hameed

Reputation: 1625

Add the RequiredAttribute to your DateTime property, then you need to make the DateTime nullable, otherwise you will get the default value for DateTime which is {0001-01-01T00:00:00}.

So basically do the followings:

public class PostModel
{
    [Required]
    public DateTime? Date { get; set; }
}

Regarding why the BindRequired did not work, I think (not 100% sure, it is just what i think) that since you are using [ApiController], it first would use [FromBody] by default, then the binding would happen after the Json.NET deserialization, so when the deserialization happens the DateTime value would be set to the Default(DateTime). To solve this you can use the old way as shown above instead of using BindRequired, or add [JsonRequired].

Note: when you use [JsonRequired] with [ApiController], validation happens before it hits your endpoint. Also note that BindRequired works well with normal MVC Controller.

Upvotes: 2

Paulo Campez
Paulo Campez

Reputation: 702

You could use RequiredAttribute instead of BindRequiredAttribute. In ASP.NET Core, the latter is only applicable for “non body” parameters

Upvotes: 1

Related Questions