4

I'm using attribute routing to override the URLs in my controller. I have two actions, with the only difference being the ID present on the second. The rest of the parameters are optional query parameters used for searching.

// RouteConfig.cs - I setup AttributeRoutes before any other mapped routes.
routes.MapMvcAttributeRoutes();

// Controllers/DeliveryController.cs
[Route("mvc/delivery")]
public ActionResult Delivery(string hauler, DateTime? startDate, DateTime? endDate, int? page)
{
    // ...
    return View(model);
}

[Route("mvc/delivery/{id}")]
public ActionResult Delivery(int id, string hauler, DateTime? startDate, DateTime? endDate, int? page)
{
    // ...
    return View("DeliverySelected", model);
}

Both routes work as expected when manually navigating to /mvc/delivery and /mvc/delivery/1234/, however links are generating incorrectly.

@Html.ActionLink("Delivery", "Delivery", new { id = delivery.ID })
@Url.Action("Delivery", new { id = delivery.ID })

Either method generates links like the following, which triggers the first action instead of the second:

http://localhost:53274/mvc/delivery?id=1234

How can I generate the expected URL instead?

http://localhost:53274/mvc/delivery/1234
Will Eddins
  • 13,628
  • 5
  • 51
  • 85

3 Answers3

3

I found the answer, thanks to this answer concerning ambiguous action methods. You can only have a maximum of 2 action methods with the same name in a controller.

I did have a third method in this case, that I left out since I thought it was unrelated:

[HttpPost]
[Route("mvc/delivery")]
public ActionResult Delivery(DeliveryViewModel model)

Renaming my second action to SelectDelivery(int id, /*...*/) solved the issue.

Community
  • 1
  • 1
Will Eddins
  • 13,628
  • 5
  • 51
  • 85
1

Since routes are order-sensitive, you need to use the Order parameter to ensure they are executed in the right order.

// Controllers/DeliveryController.cs
[Route("mvc/delivery", Order = 2)]
public ActionResult Delivery(string hauler, DateTime? startDate, DateTime? endDate, int? page)
{
    // ...
    return View(model);
}

[Route("mvc/delivery/{id}", Order = 1)]
public ActionResult Delivery(int id, string hauler, DateTime? startDate, DateTime? endDate, int? page)
{
    // ...
    return View("DeliverySelected", model);
}
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • I tried this, but it made no difference. I also tried moving the second action to be first in the file, removed all the optional parameters from both actions, and commented out the other `MapRoute`s, but none of the above has helped. – Will Eddins Aug 13 '15 at 16:00
-1

you can use following to solve it

    [Route("mvc/delivery/{hauler}/{startdate?}/{enddate}/{page?}")]
    public ActionResult Delivery(string hauler, DateTime? startDate, DateTime? endDate, int? page)
    {
        // ...
        return View(model);
    }

    [Route("mvc/delivery/{id:int}/{hauler}/{startdate?}/{enddate}/{page?}")]
    public ActionResult Delivery(int id, string hauler, DateTime? startDate, DateTime? endDate, int? page)
    {
        // ...
        return View("DeliverySelected", model);
    }
Asad Ali
  • 111
  • 2
  • 7