Pure.Krome
Pure.Krome

Reputation: 86937

Why is this MVC route not working?

here are two routes from my global.asax file. I'm trying to go to the second route and I'm getting a default 404 resource not found error.

When i remove the first route (listed in this example), it works.

How can i fix this, please?

Snippet of global.asax code

// GET: /user/PureKrome/Alert/69
routes.MapRoute(
    "User-Alert-Details",
    "user/{displayName}/alert/{alertId}",
    new { controller = "Account", action = "AlertDetails", alertId = 0 });

// GET: /user/PureKrome/Alert/create
routes.MapRoute(
    "User-Alert-Create",
    "user/{displayName}/alert/create",
    new { controller = "Account", action = "AlertCreate" });

Upvotes: 10

Views: 9785

Answers (4)

Sarfaraz Farooqui
Sarfaraz Farooqui

Reputation: 81

The problem is that you have specified Default Values for controller and actions in your first Mapping.

Now any incoming request is handled by the first route, if the controller name is missing, its replaced by the default value and if the action name is missing that is also replaced by the default value.

So in reality when you say http://localhost/SomeRoute The first mapper comes into action and considers the string "SomeRoute" as a Controller name, then it does not find the action so it uses the default action you specified which is "AlertCreate" in your example. So now the mapper tries to find a Action called AlertCreate in the "SomeRoute" controller.

Bottom line is the second mapping does not kick into action because the first mapping is handling all your routing request. (because you have default values specified)

Upvotes: 0

Morph
Morph

Reputation: 1719

If you have another issue like this, try Phil Haack's url debugger at http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx

Upvotes: 1

Erv Walter
Erv Walter

Reputation: 13788

Your first route is a "greedy" route and will happily accept "create" as the alertId in the last parameter. It appears that you intend the alertId parameter to be numeric only, so you should add a constraint to tell the route system that that last parameter must be numeric.

See this tutorial.

For example:

// GET: /user/PureKrome/Alert/69
routes.MapRoute(
    "User-Alert-Details",
    "user/{displayName}/alert/{alertId}",
    new { controller = "Account", action = "AlertDetails", alertId = 0 },
    new { alertId = @"\d+" });

// GET: /user/PureKrome/Alert/create
routes.MapRoute(
    "User-Alert-Create",
    "user/{displayName}/alert/create",
    new { controller = "Account", action = "AlertCreate" });

Note, you can also reverse the order of the routes, but even if you do, you should still include a constraint for correctness if you want alertId to always be a number.

Upvotes: 20

Garry Shutler
Garry Shutler

Reputation: 32698

You want the routes to be defined the other way round so that the exact match on create comes before the unconstrained match for alertId. That, or you can add a constraint to alertId as stated by Twisty Maze.

This is because the routing works by trying to match the routes from top to bottom. /user/PureKrome/Alert/create matches on the User-Alert-Details route as it thinks create is the value for alertId. By switching them around it will only match the User-Alert-Create route if the 4th segment is explicitly create and it will fall through to User-Alert-Details if it doesn't.

For clarity, they should work this way around:

// GET: /user/PureKrome/Alert/create
routes.MapRoute(
    "User-Alert-Create",
    "user/{displayName}/alert/create",
    new { controller = "Account", action = "AlertCreate" });

// GET: /user/PureKrome/Alert/69
routes.MapRoute(
    "User-Alert-Details",
    "user/{displayName}/alert/{alertId}",
    new { controller = "Account", action = "AlertDetails", alertId = 0 });  

Upvotes: 1

Related Questions