jrowies
jrowies

Reputation: 75

ASP.NET Web API avoid invalid parameters in query string

Given the following Web API controller action:

    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

Executing the following request is not failing, even when the parameter in the query string does not exist:

    http://localhost:22297/api/values?someinvalidparameter=10

Is there a way to ensure that all parameters in the query string are valid parameters for the action that's being invoked?

Upvotes: 7

Views: 5695

Answers (3)

gtktuf
gtktuf

Reputation: 81

For .net core web-api it will be a little different:

 public class ValidateQueryParametersAttribute : ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext actionContext)
    {

        var parameters = actionContext.ActionDescriptor.Parameters.ToList();
        var queryParameters = actionContext.HttpContext.Request.Query.Keys.ToList();

        if (queryParameters.Any(queryParameter => !parameters.Any(p => p.Name == queryParameter)))
        {
            actionContext.Result = new JsonResult(new { HttpStatusCode.BadRequest });
        }
    }
}

Upvotes: 0

RaghuRam Nadiminti
RaghuRam Nadiminti

Reputation: 6793

You can write an action filter that validates that all the query parameters are there in the action parameters and throws if not.

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace My.Namespace.Filters
{
    /// <summary>
    /// Action filter that checks that parameters passed in the query string
    /// are only those that we specified in methods signatures.
    /// Otherwise returns 404 Bad Request.
    /// </summary>
    public class ValidateQueryParametersAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// This method runs before every WS invocation
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            //check that client does not use any invalid parameter
            //but just those that are required by WS methods
            var parameters = actionContext.ActionDescriptor.GetParameters();
            var queryParameters = actionContext.Request.GetQueryNameValuePairs();

            if (queryParameters.Select(kvp => kvp.Key).Any(queryParameter => !parameters.Any(p => p.ParameterName == queryParameter)))
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }
    }
}

Upvotes: 9

tugberk
tugberk

Reputation: 58434

In order for that to work with out of the box validation support nicely, I created my own action selector which makes it possible to bind URI parameters to complex type objects without duplication.

So, you can do the following with this action selector:

public class CarsByCategoryRequestCommand {

    public int CategoryId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

public class CarsByColorRequestCommand {

    public int ColorId { get; set; }
    public int Page { get; set; }

    [Range(1, 50)]
    public int Take { get; set; }
}

[InvalidModelStateFilter]
public class CarsController : ApiController {

    public string[] GetCarsByCategoryId(
        [FromUri]CarsByCategoryRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2",
            "Car 3"
        };
    }

    public string[] GetCarsByColorId(
        [FromUri]CarsByColorRequestCommand cmd) {

        return new[] { 
            "Car 1",
            "Car 2"
        };
    }
}

Then, you can register an action filter to validate the user inputs to terminate request and return back a "400 Bad Request" response along with the validation error messages:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class InvalidModelStateFilterAttribute : ActionFilterAttribute {

    public override void OnActionExecuting(HttpActionContext actionContext) {

        if (!actionContext.ModelState.IsValid) {

            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

Check out the below posts for more information about this action selector and how you can get it:

Upvotes: 2

Related Questions