5

I have developed a custom validator Attribute class for checking Integer values in my model classes. But the problem is this class is not working. I have debugged my code but the breakpoint is not hit during debugging the code. Here is my code:

public class ValidateIntegerValueAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value != null)
            {
                int output;

                var isInteger = int.TryParse(value.ToString(), out output);

                if (!isInteger)
                {
                    return new ValidationResult("Must be a Integer number");
                }
            }

            return ValidationResult.Success;
        }
    }

I have also an Filter class for model validation globally in application request pipeline. Here is my code:

public class MyModelValidatorFilter: IActionFilter
{   
    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.ModelState.IsValid)
            return;

        var errors = new Dictionary<string, string[]>();

        foreach (var err in actionContext.ModelState)
        {
            var itemErrors = new List<string>();

            foreach (var error in err.Value.Errors){
                itemErrors.Add(error.Exception.Message);
            }

            errors.Add(err.Key, itemErrors.ToArray());
        }

        actionContext.Result = new OkObjectResult(new MyResponse
        {
            Errors = errors
        });
    }
}

The model class with validation is below:

public class MyModelClass

{

[ValidateIntegerValue(ErrorMessage = "{0} must be a Integer Value")]
[Required(ErrorMessage = "{0} is required")]
public int Level { get; set; }        

}

Can anyone please let me know why the attribute integer validation class is not working.

mnu-nasir
  • 1,642
  • 5
  • 30
  • 62

1 Answers1

11

Model validation comes into play after the model is deserialized from the request. If the model contains integer field Level and you send value that could not be deserialized as integer (e.g. "abc"), then model will not be even deserialized. As result, validation attribute will also not be called - there is just no model for validation.

Taking this, there is no much sense in implementing such ValidateIntegerValueAttribute. Such validation is already performed by deserializer, JSON.Net in this case. You could verify this by checking model state in controller action. ModelState.IsValid will be set to false and ModelState errors bag will contain following error:

Newtonsoft.Json.JsonReaderException: Could not convert string to integer: abc. Path 'Level', ...

One more thing to add: for correct work of Required validation attribute, you should make the underlying property nullable. Without this, the property will be left at its default value (0) after model deserializer. Model validation has no ability to distinguish between missed value and value equal to default one. So for correct work of Required attribute make the property nullable:

public class MyModelClass
{
    [Required(ErrorMessage = "{0} is required")]
    public int? Level { get; set; }
}
CodeFuller
  • 30,317
  • 3
  • 63
  • 79
  • 1
    I believe this answer also answers another your question - https://stackoverflow.com/questions/49300906/model-validation-is-not-working-in-asp-net-core-2-0 – CodeFuller Mar 15 '18 at 18:20
  • thanks for your great answer. It really helps me. Can you please let me know, either it is possible to handle the problem before the request handles by the JSON.Net library. Is there any way to perform some manual tasks in the application request cycle? – mnu-nasir Mar 17 '18 at 15:59
  • Both JSON.Net and ASP.NET Web API are flexible enough and provide various extensibility points for different scenarios. But could you please describe in more detail how do you want to handle such cases? Do you want JSON.Net to skip such errors (e.g. `"abc123"` for numeric field) and still deserialize model with the properties that are valid? – CodeFuller Mar 18 '18 at 12:54
  • Please let me know, what should I do in that case? – mnu-nasir Mar 19 '18 at 05:40
  • But on this stage you will not yet have an access to the model or `HttpContext`. So when you encounter such error you don't have proper way to register it for further validation. I'm not quite sure I fully understand your use case - why you wan't to validate integer parsing while JSON.Net does it for you and provides proper errors and model state. – CodeFuller Mar 20 '18 at 04:53
  • 1
    The last paragraph of this answer is wonderful; I have been searching for an hour to find this out. – Ed Graham Sep 28 '22 at 21:22