views:

46

answers:

2

Hi all,

I've a small issue with URL generation & routing under ASP.NET MVC 2. My route has optional parameters and the URL is correctly generated if the parameters are specified.

Thus:

routes.MapRoute("Blog", "Articles/{tag}/{page}", new { controller = "Blog", action = "Index" });

with:

<%: Html.ActionLink(item.Tag, "Index", "Blog", new { tag = item.Tag }, null) %>

does correctly generates ~/Articles/item_tag/1. The link works, my view is rendered.

I have others link like:

<%: Html.ActionLink("See more articles", "Index", "Blog") %>

that generates ~/Blog instead of ~/Articles.

If I add a second route like:

routes.MapRoute("Blog2", "Articles", new { controller = "Blog", action = "Index" });

my URL is correctly rendered. I can't understand why I'd need to add this second route as it seems very redundant because the first route has optional segments.

Any help appreciated.

Fabian

EDIT: added routes code.

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

// Home
routes.MapRoute("Home", "", new { controller = "Home", action = "Index" });
routes.MapRoute("HomeSearch", "Search", new { controller = "Home", action = "Search" });

// Solutions
routes.MapRoute("Solutions", "Solutions", new { controller = "Home", action = "Solutions" });

// Customers
routes.MapRoute("Customers", "Customers", new { controller = "Home", action = "Customers" });

// News
routes.MapRoute("NewsDetails", "News/Details/{id}", new { controller = "News", action = "Details" });
routes.MapRoute("News", "News", new { controller = "News", action = "Index" });

// Articles
routes.MapRoute("BlogDetails", "Articles/Details/{id}", new { controller = "Blog", action = "Details" });
routes.MapRoute("BlogWithTag", "Articles/{tag}/{page}", new { controller = "Blog", action = "Index", tag = "", page = 1 });
routes.MapRoute("Blog", "Articles/{page}", new { controller = "Blog", action = "Index", page = 1 });

// Contact
routes.MapRoute("Contact", "Contact", new { controller = "Contact", action = "Create" });

// Sitemap
routes.MapRoute("Sitemap", "SiteMap", new { controller = "Home", action = "SiteMap" });
A: 

In this:

routes.MapRoute("Blog", "Articles/{tag}/{page}", new { controller = "Blog", action = "Index" });

The {tag} and {page} tokens are not optional. They are hard-coded into the URI and you have no default for them.

Because of the / between {tag} and {page} in your route, this will never generate a URI like ~/Blog.

Craig Stuntz
It will if there's another route definition that starts with `"Blog/..."`
Robert Koritnik
@Robert, of course. He's asking why the one route does not.
Craig Stuntz
So your suggestion is to keep my "Blog2" route?
Fabian Vilers
Yes, probably. Hard to be certain without working out a full routing strategy. You should do that, incidentally.
Craig Stuntz
A: 

Non-optional parameters are mandatory

As their name implies, they are nonoptional. So if you don't provide tag and page in your ActionLink() call, route won't hit this route definition.

So your example when you call Html.ActionLink() and provide tag parameter but not page I guess you must have a different route definition that starts with Article/... as well, because your route that you've provided here, is unable to generate your link:

/Articles/item_tag/1

Route doesn't have any knowledge of parameter types. This means that parameter page value was provided by other means either by:

  • existing page route data values
  • a different route definition

So what's in it for you?

What's important in your case is that not providing tag and page parameter values when generating links, your route definition won't get hit and your link will be incorrect.

Why did you actually get /Blog link? Simply because you probably still have the default route definition at the end:

{controller}/{action}/{id}

And since you did say that controller is Blog and action is Index but haven't provided Id, so it will use its default, this will generate your default link URL which is exactly /blog. It's quite obvious when you look at it this way isn't it?

Robert Koritnik
Thanks, I thought that having my controller method with optional parameters would suffice. I've modified my Global.asax.cs file like this:routes.MapRoute("Blog", "Articles/{tag}/{page}", new { controller = "Blog", action = "Index", tag = "", page = 1 });But it still doesn't generates the right URL.
Fabian Vilers
@Fabian Vilers: If you provide your complete route definition from Global.ascx.cs (add it to your question and format it), we will be able to help. **Why?** Simply because it should work with one route that defines defaults for `tag` and `page`. There's no need for second route definition whatsoever if those two parameters have defaults.
Robert Koritnik
Hi, i've edited my post.
Fabian Vilers