Search code examples
asp.netasp.net-web-api2asp.net-web-api-routing

How to prevent random queries from being matched to an action annotated with [Route('')]?


I currently have this controller

[RoutePrefix("api/Home")]
public class HomeController : ApiController
{

    [HttpGet]
    [Route("")]
    public IHttpActionResult GetByIdAndAnotherID([FromUri]int? id = null, [FromUri]int? AnotherId = null){

        if (!ModelState.IsValid) //From ApiController.ModelState
        {
            return BadRequest(ModelState);
        }
    }
}

I want only the following 3 urls to be matched:

  1. api/Home (Both id and AnotherId are null)
  2. api/Home?id=1 (Only Anotherid is null)
  3. api/Home?AnotherId=1 (Only Id is null)

Other urls should return unregistered routes or error. Currently, api/Home?asdfanyquery also returns a match which is not what I desired.

How do I rewrite the controller so that the routes only matches to the 3 urls above?


Solution

  • I ended up creating an ActionFilterAttribute as suggested in the comments and applying it like so:

    public class InvalidQueryStringRejector : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var arguments = actionContext.ActionArguments.Keys;
    
            var queryString = actionContext.Request.GetQueryNameValuePairs()
                .Select(q => q.Key);
    
            var invalidParams = queryString.Where(k => !arguments.Contains(k));
    
            if (invalidParams.Any())
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, new
                {
                    message = "Invalid query string parameters",
                    parameters = invalidParams
                });
            }
        }
    }
    
    
    [RoutePrefix("api/Home")]
    public class HomeController : ApiController
    {
         [InvalidQueryStringRejector] //The custom created ActionFilterAttribute
         [HttpGet]
         [Route("")]
         public IHttpActionResult GetByIdAndAnotherID([FromUri]int? id = null, [FromUri]int? AnotherId = null)
         {
             if (!ModelState.IsValid) //From ApiController.ModelState
             {
                  return BadRequest(ModelState);
             }
         }
    }