ASP.NET Web API and greedy query string parameter binding

Strath

April 28th, 2013

ASP.NET Web API and greedy query string parameter binding

Following the last article on parameter binding from URI, I received an interesting question – “what if I wanted to prevent binding parameters from query string and only allow binding from route values”? In other words, prevent passing values to actions via query strings and only look for them in the route itself (to avoid duplicate ways of reaching the same endpoint).

This is possible in Web API – let’s explore how you’d go about implementing it.

More after the jump.

The problem of greedy query strings in ASP.NET Web API

Imagine you have a simple controller and a nice route associated with it:

You’d expect your users to invoke the action accordingly:

But if you keep the default route, this will also be possible:

If you are an API purist, you probably want to prevent it. There is, an easy way to enforce parameter binding from Route Data only, instead of greedily looking into the query string as well.

Global

One option is to do it globally against your HttpConfiguration.

With this simple one liner, you replace the default setting which is using both RouteDataValueProviderFactory and QueryStringValueProviderFactory with just the first one. The latter, as the name suggests, yields the QueryStringValueProvider which is responsible for the greedy lookup into the query string.

Of course doing this change at this level, means that you now have this behavior for every single action.

Per controller

For a more granular control, you can look into a per-controller configuration – which would allow you to move the same setting down to a controller-level

This way the binding from query string will not work only for this specific controller.

Per parameter

Finally, you can also use the ValueProvider attribute to apply a specific factory to a single attribute too.

While this looks a little less readable, it gives you the ultimate control in terms of where Web API should look for the parameter value.

Other considerations

Remember, we are only enforcing policies on how the values of the parameters should be extracted in the request here.

It is important to add that action selection mechanism will still look into query string when trying to find a relevant action to execute. To circumvent this, you’d need to implement a custom IActionSelector, but that’s global for the whole API.

In other words, by applying any of the technique showed here, you should not expect that a request to /api/test?p1=hello&p2=world will be treated as a request to /api/test and routed to a different action.

Instead, the old action will still be selected – just the parameter values passed to the action will be null. Therefore, it is quite common (and sensible) to use this in conjunction with checking the parameters for null values:

So the final solution might look like this:

Hopefully you’ll find this useful at some point.

Be Sociable, Share!