In my table I have two links:
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Events", "LocationEvents", "Events", new {locationId = item.Id}, null)
Now my goal is when I hover over the links I want the url to look like this for both:
/Locations/Edit/4
/Events/LocationEvents/4
However, I am getting this:
/Locations/Edit?id=4
/Events/LocationEvents/4
Here is my RouteConfig.cs
routes.MapRoute(
name: "Events",
url: "{controller}/{action}/{locationId}",
defaults: new {controller = "Locations", action = "Index", locationId = UrlParameter.Optional}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Locations", action = "Index", id = UrlParameter.Optional }
);
How do I make this work?
Simply, you can't have two routes like this. They're both functionally the same, taking a controller, action and some sort of id value. The fact that the id param names are different is not enough to distinguish the routes.
First, you'd need to distinguish the routes by hard-coding one of the params. For example, you could do something like:
routes.MapRoute(
name: "Events",
url: "Events/{action}/{locationId}",
defaults: new {controller = "Locations", action = "Index", locationId = UrlParameter.Optional}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Locations", action = "Index", id = UrlParameter.Optional }
);
Then, the first route would only match the URL begins with "Events". Otherwise, the default route will be used. That's necessary to handle the routing properly when the client requests the URL. It still doesn't help you in terms of generating the route, as UrlHelper
doesn't have enough information to determine which one to choose. For that, you'd need to use the route name to explicitly tell it which one to use:
@Html.RouteLink("Default", new { controller = "Edit", action = "edit", id = item.Id })
Frankly, the RouteConfig-style routing is a huge pain. Unless, you're dealing with a very simple structure that can pretty much just be handled by the default route, then you'd be much better off using attribute routing, where you describe the exact route each action should have. For example:
[RoutePrefix("Events")]
public class EventsController : Controller
{
...
[Route("LocationEvents", Name = "LocationEvents")]
public ActionResult LocationEvents(int locationId)
{
...
}
}
Then, it's absolute explicit, and if you want to make sure you're getting exactly the right route, you can just utilize the name (in conjunction with Html.RouteLink
, Url.RouteUrl
, etc.).