切换到 {controller}/{id}/{action} 会破坏 RedirectToAction。

9

我正在尝试使用适当的 REST URL 与 MVC 结合使用。为此,我将默认路由从以下内容切换:

{controller}/{action}/{id}

to

{controller}/{id}/{action}

所以不是这样的:
/Customer/Approve/23

现在有一个问题。
/Customer/23/Approve

ActionLink似乎工作正常,但是在CustomerController中的以下代码:

[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
    _customerService.Approve(id);
    return RedirectToAction("Search");  //Goes to bad url
}

最终跳转到了url /Customer/23/Search,但实际应该跳转到/Customer/Search。不知何故它记住了23 (id)

以下是我在global.cs中的路由代码:

    routes.MapRoute(
        "AdminRoute", // Route name
        "{controller}/{id}/{action}", 
        new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        new { id = new IsIntegerConstraint() }
        );

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

如果我交换这两个函数,RedirectToAction 就会开始工作,但是使用:
Html.ActionLink("Approve", "Approve", new { Id = 23})

现在生成的链接是/Customer/Approve?id=23,而不是/Customer/23/Approve
我可以直接指定URL,例如~/Customer/23/Approve,而不使用ActionLinkRedirectToAction,但我更愿意使用MVC提供的功能。

2
我想知道 id 上的 UrlParameter.Optional 是否会对此产生影响。 - Peter Mourfield
奇怪的是UrlParameter只有一个值"Optional",如果像"Required"这样的东西可能会让它工作。 - Eric P
6个回答

2
当您使用RedirectToAction()时,MVC会在内部获取现有的路由数据(包括Id值)来构建URL。即使您传递了一个null的RouteValueDictionary,现有的路由数据也将与新的空路由值数据合并。
我唯一能想到的解决方法是使用RedirectToRoute(),如下所示:
return RedirectToRoute("Default", new { controller = "Customer", action = "Search"});

counsellorben


不幸的是,这仍然会在URL中保留客户ID,最终变成/Customer/23/Search。 - Eric P

1
尝试在您的控制器中传递新的(空)RouteValueDictionary。
return RedirectToAction("Search", new System.Web.Routing.RouteValueDictionary{});

这里:

Html.ActionLink("Approve", "Approve", new { Id = 23})

我甚至不知道它如何选择客户控制器,因为您没有在任何地方指定它。尝试向ActionLink助手提供控制器和操作。


如果您在控制器内调用RedirectToAction("action"),则ControllerName是可选的。如果您在控制器的视图中执行ActionLink,似乎也可以使用相同的方式。它只是使用当前控制器。 - Eric P
是的,但是为了更高的确定性水平,当你遇到无法解释的问题时,你应该指定控制器,不是吗? - mare
“additional level of certainty” 的观点很好。我尝试添加控制器名称,但没有变化。 - Eric P

0

尝试将当前路由数据传递给你控制器动作中的方法:

return RedirectToAction("Search", this.RouteData.Values);

0
删除这部分:
id = UrlParameter.Optional

也许可以解决这个问题;当您将"id"定义为可选参数,并且有"Default"映射时,"Default"和"AdminRoute"就会合并在一起!祝好。


0
我遇到了类似的问题。当我尝试用RedirectToAction重定向用户时,传递给我的控制器操作的路由值会被重复使用,即使我在新的RouteValueDictionary中没有指定它们。在阅读counsellorben的帖子后,我想出了一个解决方案,就是清除当前请求的RouteData。这样,我就可以阻止MVC合并我没有指定的路由值。
所以,在你的情况下,也许你可以像这样做:
[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
    _customerService.Approve(id);
    this.RouteData.Values.Clear();  //clear out current route values
    return RedirectToAction("Search");  //Goes to bad url
}

0

我曾经遇到过类似的问题,通过在默认路由中添加id,我成功地解决了它。

routes.MapRoute(
    "Default", 
    "{controller}/{action}/{id}", 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional });

如果默认路由确实没有ID,那么您也可以尝试以下方法:
routes.MapRoute(
    "Default", 
    "{controller}/{action}", 
    new { controller = "Home", action = "Index", id = string.Empty });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接