Question

I've got a fairly lengthy Get() method in an ASP.NET Web API controller. Something like this:

public PaginatedResult Get(int perPage = 10, int pageNum = 0, string param1 = null, [...] string param20 = null)

What I'd like is to be able to handle circumstances where a request includes a query param that's not part of the method signature. That is, if someone requests this:

/?perPage=10&paran19=foo&param21=bar

...I want to be able to say, "hey there, neither 'paran19' nor 'param21' exist, so they won't affect the results of this query!"

The only way I can think of to handle this is to call GetQueryNameValuePairs() on the Request, and then use reflection to compare that list with the params accepted by my Get() method. That seems like overkill for this problem though. Is there a better way? Ideally one flexible enough to be easily applied to several methods.

Was it helpful?

Solution

So, hopefully this self-answer isn't poor form on S.O., but with a little prodding from Cj S.'s answer, I looked more into the Web API message lifecycle, and ended up creating an Action Filter:

public class QueryParamMatchingActionFilter : ActionFilterAttribute
{

    public override void OnActionExecuting(HttpActionContext filterContext)
    {
        List<string> queryParamNames = filterContext.Request.GetQueryNameValuePairs().Select(q => (string)q.Key.ToLowerInvariant()).ToList();

        List<string> methodParams = filterContext.ActionArguments.Select(q => (string)q.Key.ToLowerInvariant()).ToList();

        List<string> unrecognized = queryParamNames.Where(qp => !methodParams.Any(mp => mp == qp)).ToList();

        if (unrecognized.Count > 0)
        {
            List<string> errors;
            if (filterContext.Request.Properties.ContainsKey("MY_ERRORS"))
                errors = (List<string>)filterContext.Request.Properties["MY_ERRORS"];
            else
                errors = new List<string>();

            foreach (string badParam in unrecognized)
            {
                errors.Add(String.Format("UNRECOGNIZED PARAMETER IGNORED: {0}", badParam));
            }

            filterContext.Request.Properties["MY_ERRORS"] = errors;
        }
    }

}

So now I can just decorate my controllers with "[QueryParamMatchingActionFilter]". The contents of MY_ERRORS get put into the response by a DelegatingHandler I already had setup, which wraps responses with some useful metadata. But this code should be easy enough to repurpose toward doing other things with extraneous params. The ability to use the ActionArguments property of filterContext means we get to skip using reflection, but I still wouldn't be surprised if someone else knew of a more efficient way to do this!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top