ASP .NET CORE simple parameter validation

13,660

Solution 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

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

Share:
13,660

Related videos on Youtube

Kane
Author by

Kane

Updated on June 04, 2022

Comments

  • Kane
    Kane almost 2 years

    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?

  • zameb
    zameb about 4 years
    This answer helped me a lot. Also worth to mention that you can set the compatibility to a different version with services.AddMvc().SetCompatibilityVersion(CompatibilityVersi‌​on.Version_2_2); and you can also set the behavior of parameters (a "top level node") with services.AddMvc(options => { options.AllowValidatingTopLevelNodes = false; }); both in Startup.ConfigureServices method
  • Jeff Mercado
    Jeff Mercado over 3 years
    Looks like the code was swiped from here: blog.markvincze.com/…