16

What's the best way to handle a visitor constructing their own URL and replacing what we expect to be an ID with anything they like?

For example:

ASP.Net MVC - handling bad URL parameters

But the user could just as easily replace the URL with:

https://stackoverflow.com/questions/foo

I've thought of making every Controller Function parameter a String, and using Integer.TryParse() on them - if that passes then I have an ID and can continue, otherwise I can redirect the user to an Unknown / not-found or index View.

Stack Overflow handles it nicely, and I'd like to too - how do you do it, or what would you suggest?

5 Answers 5

12

Here's an example of a route like yours, with a constraint on the number:

routes.MapRoute(
    "Question",
    "questions/{questionID}",
    new { controller = "StackOverflow", action = "Question" },
    new { questionID = @"\d+" } //Regex constraint specifying that it must be a number.
);

Here we set the questionID to have at least one number. This will also block out any urls containing anything but an integer, and also prevents the need for a nullable int.

Note: This does not take into account numbers that larger than the range of Int32 (-2147483647 - +2147483647). I leave this as an exercise to the user to resolve. :)

If the user enters the url "questions/foo", they will not hit the Question action, and fall through it, because it fails the parameter constraint. You can handle it further down in a catchall/default route if you want:

routes.MapRoute(
    "Catchall",
    "{*catchall}", // This is a wildcard routes
    new { controller = "Home", action = "Lost" }
);

This will send the user to the Lost action in the Home controller. More information on the wildcard can be found here.

NB: The Catchall should reside as the LAST route. Placing it further up the chain will mean that this will handle all others below it, given the lazy nature of routes in ASP.NET MVC.

Sign up to request clarification or add additional context in comments.

6 Comments

Instead of that last line: 'new { questionID = @"\d{1,}" }', Scott Hanselman uses a slightly shorter syntax of: 'new { questionID = @"\d+" }' to mean the same thing. Source: asp.net/learn/mvc-videos/video-7093.aspx
Yes, the two are pretty much the same thing. I tend to put mine in curly braces like that because I dynamically create my routes from the database, and it saves me a bit of logic when I want to explicitly specify the maximum number of digits.
Why is your url "{catchall}"? What does the '' signify?
@Ragepotato: It's a wildcard.
The problem of regex is that "\d+" allows numbers greater than Int32.MaxValue. Because of that I wrote own Int32Constraint that checks it. Though I am not sure it is the best practice or not.
|
5

Here is some useful infromation that might help. If you have a action method

public ActionResult Edit(int? id)
{}

then if someone types in

/Home/Edit/23

the parameter id will be 23. however if someone types in

/Home/Edit/Junk

then id will be null which is pretty cool. I thought it would throw a cast error or something. It means that if id is not a null value then it is a valid integer and can be passed to your services etc. for db interaction.

Hope this provides you with some info that I have found whilst testing.

1 Comment

Additionally, there will be a model error present in ModelState which reflects the problem with parameter "id".
4

In ASP.NET MVC, you can define a filter implementing IActionFilter interface. You will be able to decorate your action with this attribute so that it will be executed on, before or after your action.

In your case, you will define it to be executed "before" your action. So that, you will be able to cancel it if there is an error in the passed parameters. The key benefit here that you only write the code which checking the passed paramaters once (i.e you define it in your filter) and use it wherever you want in your controller actions.

Read more about MVC filters here: http://haacked.com/archive/2008/08/14/aspnetmvc-filters.aspx

Comments

2

You can specify constraints as regular expressions or define custom constraints. Have a look at this blog post for more information:

http://weblogs.asp.net/stephenwalther/archive/2008/08/06/asp-net-mvc-tip-30-create-custom-route-constraints.aspx

You will still need to deal with the situation where id 43243 doesn't map to anything which could be dealt with as an IActionFilter or in your controller directly.

Comments

0

The problem with that approach is that they still might pass an integer which doesn't map to a page. Just return a 404 if they do that, just as you would with "foo". It's not something to worry about unless you have clear security implications.

1 Comment

Sure, I'd have to check the Integer is valid, but is using String as the Function parameter type the way to go? - the TaskList example (asp.net/learn/mvc/tutorial-01-cs.aspx ~35min 43s) strongly types the ID to Integer and this results in an error when 'foo' is passed in :o/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.