8

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?

1

2 Answers 2

11

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://learn.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://learn.microsoft.com/en-us/aspnet/core/web-api/index?view=aspnetcore-2.1#automatic-http-400-responses

Sign up to request clarification or add additional context in comments.

1 Comment

This answer helped me a lot. Also worth to mention that you can set the compatibility to a different version with services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.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
8

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
    }
}

1 Comment

Looks like the code was swiped from here: blog.markvincze.com/…

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.