2

I am struggling to get my head around routing in MVC3.

Previously I have generally just avoided the whole area and stuck with ugly old ?id=1&foo=bar type urls. Not nice.

I have 4 routes defined thusly

routes.MapRoute("Blog", "{controller}/{action}/{PageNumber}/{PostsPerPage}", new { controller = "blog", action = "list", PageNumber = UrlParameter.Optional, PostsPerPage = UrlParameter.Optional });
routes.MapRoute("Code", "{controller}/{action}/{title}", new { });
routes.MapRoute("Id", "{controller}/{action}/{id}", new { });
routes.MapRoute("Default", "{controller}/{action}", new { controller = "home", action = "index" });

I have tried to order them from most specific to least.

The first 'blog' route works fine and I can use a URL like /blog/list/2/5 and it maps correctly to my controller.

The default route at the bottom is also working as I would expect.

However if I have action methods like this:

public ActionResult BarX(int id)
{
    //some stuff
}

public ActionResult BarY(string title)
{
    //some stuff
}

I would expect it to use the third route and produce a URL like /foo/barX/3.

Yet if I use

@Html.ActionLink("TEST1", "barX", "foo", new { id = 3 }, null)

the URL generated is

/foo/barx?id=3

Similarly the URL generated for

@Html.ActionLink("TEST2", "barY", "foo", new { title = "test" }, null)

is

/foo/bary?title=test

So I guess my question is: why are they producing URLs with the old ?id= syntax and not /foo/barx/3?

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
glosrob
  • 6,631
  • 4
  • 43
  • 73

1 Answers1

9

All of your routes are basically the same. They are

{controller}/{action}/{param}/{param}

I say the same because the routing engine would not understand the difference between {controller}/{action}/{id} and {controller}/{action}/{title}

and the route engine would really just see

{controller}/{action}/{PageNumber}/{PostsPerPage}

and confuse all the routes with the first one.


Once the route engine sees your almost generic {optional}/{optional}/{optional}/{optional}/ route at the top, anything with 4 or fewer elements can fit it so it goes no further.


If, on the other hand, your routes had distinctive beginnings, rather than generic {Controller}:

routes.MapRoute("Blog", "Blog/{PageNumber}/{PostsPerPage}", new { controller = "blog", action = "list", PageNumber = UrlParameter.Optional, PostsPerPage = UrlParameter.Optional });
routes.MapRoute("Code", "Code/{title}", new { controller = "code", action = "list", title = UrlParameter.Optional });
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "home", action = "index", id = UrlParameter.Optional });

Now, every time the routing engine sees Blog/... it understands that only 1 route can match. With all others, it will move on looking for a match. Whenever it sees Code/..., again only 1 route is a match. And Default will handle anything like {Controller}/{Action}/{id} that doesn't have Blog or Code as a first route param.

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101