'ASP .NET CORE simple parameter validation

Is it possible to do some validation using attributes on simple parameters, like:

[HttpGet("test/{type}")]
public ActionResult  GetSomeData([Range(0,2)]byte type)
{
  if (!ModelState.IsValid)
  {
    // isValid is always TRUE
  }
  ...
}

When you call /controller/test/4, IsValid is always TRUE.

Is there a cleaner way to do that?



Solution 1:[1]

You can create a custom filter attribute to instruct MVC pipeline to do the validation:

public class ValidateActionParametersAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var descriptor = context.ActionDescriptor as ControllerActionDescriptor;

        if (descriptor != null)
        {
            var parameters = descriptor.MethodInfo.GetParameters();

            foreach (var parameter in parameters)
            {
                var argument = context.ActionArguments[parameter.Name];

                EvaluateValidationAttributes(parameter, argument, context.ModelState);
            }
        }

        base.OnActionExecuting(context);
    }

    private void EvaluateValidationAttributes(ParameterInfo parameter, object argument, ModelStateDictionary modelState)
    {
        var validationAttributes = parameter.CustomAttributes;

        foreach (var attributeData in validationAttributes)
        {
            var attributeInstance = CustomAttributeExtensions.GetCustomAttribute(parameter, attributeData.AttributeType);

            var validationAttribute = attributeInstance as ValidationAttribute;

            if (validationAttribute != null)
            {
                var isValid = validationAttribute.IsValid(argument);
                if (!isValid)
                {
                    modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name));
                }
            }
        }
    }
}

Then add it to the action:

[HttpGet("test/{type}")]
[ValidateActionParameters]
public ActionResult GetSomeData([Range(0, 2)]byte type)
{
    if (!ModelState.IsValid)
    {
       // isValid has correct value
    }
}

Solution 2:[2]

As of version 2.1, this functionality is now available out of the box; data annotations on action parameters will also be respected when calling ModelState.IsValid in the same way that they are on models.

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-2.1#top-level-node-validation

If you annotate your class with the ApiController attribute, validation will also be performed automatically, and a 400 Bad Request will be returned with details of the invalid data without having to call ModelState.IsValid yourself.

https://docs.microsoft.com/en-us/aspnet/core/web-api/index?view=aspnetcore-2.1#automatic-http-400-responses

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Riabov
Solution 2 adrian