ASP.NET Core ModelState Validation Filter

During my code review sessions I see a lot of duplicate for the ModelState validation like

public async Task<IActionResult> AddAsync(PersonAddSubmitModel model)
{
    if(ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // ......
}

But it makes no sense to use the same code in every action to validate your submit model. It can be easier!

Validation Filter


    public class ModelStateValidationAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }

With this attribute you can save a lot of redudant code:

[ModelStateValidation]
public async Task<IActionResult> AddAsync(PersonAddSubmitModel model)
{
    // ......
}

Pro Tip: Use IValidatableObject

I am not a big fan of the DataAnnotation attributes.

But I really like IValidatableObject because it also gives you a context with the posibility to not only validate some plain input texts, you also can access o your dependency injected services and validate against logic or your database.

ASP.NET Core automatically validates all input models if they implement IValidatableObject.

public abstract class BaseSubmitModel : IValidatableObject
{
    public abstract IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
}

public class PersonAddSubmitModel : BaseSubmitModel
{
    public string Name {get;set;}

    public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
    {
        if(string.IsNullOrWhiteSpace(Name)) yield return new ValidationResult($"{nameof(Name)} is missing.", new [] {nameof(Name)})
    }
}