ActionLink 为属性路由生成错误的 URL

ActionLink generates wrong URL for Attribute Route

我正在使用属性路由来覆盖我控制器中的 URL。我有两个动作,唯一的区别是第二个动作的 ID。其余参数是用于搜索的可选查询参数。

// 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);
}

当手动导航到 /mvc/delivery/mvc/delivery/1234/ 时,两条路线都按预期工作,但链接生成不正确。

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

这两种方法都会生成如下链接,触发第一个动作而不是第二个动作:

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

如何生成预期的 URL?

http://localhost:53274/mvc/delivery/1234

由于路由是顺序敏感的,您需要使用 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);
}

感谢 this answer concerning ambiguous action methods,我找到了答案。在一个控制器中最多只能有 2 个同名的操作方法。

在这种情况下我确实有第三种方法,但由于我认为它不相关而被遗漏了:

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

将我的第二个操作重命名为 SelectDelivery(int id, /*...*/) 解决了这个问题。

可以用下面的方法解决

    [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);
    }