1

I have the following endpoint in my controller, and I would like to create a custom validation for attribute passed from query.

[ApiController]
public class SampleController : ControllerBase
{
    [HttpGet]
    [Route("api/user")]
    public IActionResult GetUsersByLevel(
        [BindRequired, ValidLevelFromQuery(Name = "level")] string level)
    {
        ...
    }
}

My desired outcome is that I create a custom FromQuery attribute, which in this sample I describe as ValidLevelFromQuery. The custom attribute would check the value of level and would only accept "A", "B", and "C", on any other value, the response to the client will be a BadRequest.

Currently I am doing the validation after I have read the value in the action. My goal is have this check earlier in the request pipeline.

I would like to avoid using IValidatableObject if possible.

Vergil C.
  • 1,046
  • 2
  • 15
  • 28
  • You can create a custom attribute and have your logic there, and then add the attribute to your parameter, like BindRequired. – Aspram May 02 '20 at 00:23
  • https://stackoverflow.com/questions/52977418/validate-query-parameters-without-using-a-model-in-netcore-api/52977922 might be helpful – Aspram May 02 '20 at 00:26
  • Thanks, managed to draw a solution based on your suggestions. – Vergil C. May 11 '20 at 17:48

1 Answers1

2

You can use ActionFilter to achieve this.

Please refer to the following code:

        [HttpGet]
        [Route("api/user")]
        [ValidLevelFromQuery]
        public IActionResult GetUsersByLevel(
           [BindRequired] string level)
        {
            return Ok();
        }

ValidLevelFromQuery method:

public class ValidLevelFromQueryAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// Validates Level automaticaly
        /// </summary>
        /// <param name="context"></param>
        /// <inheritdoc />
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (context.ActionArguments.ContainsKey("level"))
            {
                string[] allowedGroup = new string[] { "A", "B", "C" };
                if (!allowedGroup.Contains(context.ActionArguments["level"]))
                {
                    context.Result = new BadRequestObjectResult("The level is not allowed");
                }
            }
        }

Here is the test result:

enter image description here

LouraQ
  • 6,443
  • 2
  • 6
  • 16
  • Found a solution based on Aspram's comments, which is exactly what you have answered. Thanks for taking the time to answer and will accept your answer so others can see it. – Vergil C. May 11 '20 at 17:50