6

I'm trying to return a custom response object when a model fails validation in my Web API project. I have attached attributes to the model like this:

  public class DateLessThanAttribute : ValidationAttribute
  {
    private readonly string _comparisonProperty;

    public DateLessThanAttribute(string comparisonProperty)
    {
      _comparisonProperty = comparisonProperty;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
      ErrorMessage = ErrorMessageString;
      var currentValue = (DateTime)value;

      var property = validationContext.ObjectType.GetProperty(_comparisonProperty);

      if (property == null)
        throw new ArgumentException("Property with this name not found");

      var comparisonValue = (DateTime)property.GetValue(validationContext.ObjectInstance);

      if (currentValue > comparisonValue)
        return new ValidationResult(ErrorMessage);

      return ValidationResult.Success;
    }
  }

On the model:

[DateLessThan("EndDate", ErrorMessage = "StartDate must be less than EndDate")]
public DateTime StartDate { get; set; }

And the controller:

public void PostCostingStandard(CostStandardRequest request)
{
  CostResult costResult;
  if (ModelState.IsValid)
  {
    // work
  }
  else
  {
    // return bad costResult object
  }
}

However, the model never reaches inside the controller to hit ModelState.IsValid. I've tried creating an ActionFilterAttribute and attaching it to my controller action as outlined here, but when setting a breakpoint, the ActionFilterAttribute never runs because the DateLessThanAttribute returns a response first. Is there an order to these filters that I've missed or have I simply implemented something incorrectly?

1
  • What exactly do you mean by the model never reaches inside the controller? How exactly are you testing your application? Commented Nov 6, 2018 at 17:38

1 Answer 1

8

You have to disable automatic model state validation. You can do so by adding the following code to your startup.cs

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});
Sign up to request clarification or add additional context in comments.

7 Comments

I think you are refering to ASP .Net Core. It seems to me the question is related to ASP .Net
It's possible. I will delete the answer if this is the case.
This is a .Net Core app, sorry I didn't state that clearly! Adding this worked perfectly for me, thanks. Just wish I would've found it stated more explicitly somewhere..
@Danijel You are disabling the default behaviour just to make your code work which will end up with duplication in each ActionMethod.
@Voodoo It's not duplication because, in my particular case, we are handling the "error" a little differently. We are returning a more complex JSON object describing what's wrong with custom code + custom validation message + logging the error/sending email + other business logic depending on the case. This default behavior is meant for the most basic use-case while most more "serious" API's often need the control over handling bad requests.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.