MVC 路由未保留在 RedirectToAction 上

MVC route not kept on RedirectToAction

我有这样的路由配置:

routes.MapRoute(
           "routeB",
           "routeB/{action}/{id}",
           new { controller = "Sample", action = "IndexB", id = UrlParameter.Optional });

        routes.MapRoute(
           "routeA",
           "routeA/{action}/{id}",
           new { controller = "Sample", action = "IndexA", id = UrlParameter.Optional });

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

我的示例控制器包含这些操作方法:

 public ActionResult IndexA(string id)
    {

        return View("Index");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult IndexA()
    {
        return RedirectToAction("Confirmation");
    }

    public ActionResult Confirmation()
    {
        return View("Confirmation");
    }

    public ActionResult IndexB(string id)
    {
        return View("Index");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult IndexB()
    {
        return RedirectToAction("Confirmation");
    }

如果我登陆 localhost/RouteA 页面并创建 POST(通过按钮),它会将我重定向到 localhost/RouteB/Confirmation。

如何让页面重定向到 RouteA/Confirmation 页面?

谢谢。

你的问题很简单。 查看您的控制器,IndexA 和 IndexB 方法,returns 相同的视图; (来自您的评论)

@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } 

<h2>Index</h2>

using (Html.BeginForm("IndexB", "Sample", new { @id = "OrderForm" })) { 

@Html.AntiForgeryToken() 
<button type="submit" id="orderFormBtn">Extend my discount.</button> 
}

当您点击提交时,您总是会执行 post 到 IndexB

有很多方法可以纠正这种简单的错误,例如,您可以简单地使用 2 个不同的视图 IndexAIndexB 并更改

using (Html.BeginForm("IndexB", "Sample", new { @id = "OrderForm" })) {

using (Html.BeginForm("IndexA", "Sample", new { @id = "OrderForm" })) {

问题是您的 routeArouteB 路由都可以为 SampleController 中的 IndexA 操作创建 link。因此,BeginForm 只会 short-circuit 并选择第一条可行的路线,这可能是也可能不是您正在寻找的 "correct" 路线。为了区分路由,通过路由名称生成它们:

@using (Html.BeginRouteForm("routeA", new { @id = "OrderForm" })) {

然而,这只会让你获得 "default" routeA 路线,即 /routeA/。除了路由的默认操作之外,无法指定其他操作。

为了获得更大的灵活性,您可以使用属性路由,这将允许您为每个操作指定一个自定义路由名称,然后您可以使用它来获取该操作的 URL。

除此之外,您将需要以某种方式区分这两条路线,以便在生成 URL 时应该使用哪条路线不会产生歧义。使用标准路由通常很难做到这一点,这就是为什么属性路由是更好的方法,如果您不打算对所有内容简单地使用默认路由。

或者,您可以重组项目以保持相同的 URL 结构,但更容易区分路线。通过使用区域,您可以指定应从中创建路径的区域。例如,假设您有 RouteARouteB 区域,您可以这样做:

@using (Html.BeginForm("IndexB", "Sample", new { area = "RouteA", @id = "OrderForm" })) { 

那就意味着每个区域都有一个 SampleController,但是您可以使用继承来重用代码。

这里有两个问题。正如其他人指出的那样,您的 HTTP POST 需要更正。由于您要为 2 个不同的操作共享一个视图,因此最简单的方法是将 actionName 参数设置为 null。这告诉 MVC 使用当前请求中的操作名称。

@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; }

<h2>Index</h2>

@using (Html.BeginForm(null, "Sample", new { id = "OrderForm" }))
{

    @Html.AntiForgeryToken()
    <button type="submit" id="orderFormBtn">Extend my discount.</button>
}

第二个问题是在生成 URL 时,RedirectToAction 调用在 routeArouteB 之间不明确。由于第一个匹配项总是获胜,因此您重定向到的 URL 始终是您配置中的第一个匹配项。

您可以通过使用 RedirectToRoute 明确指定路由名称(除了您现有的匹配条件之外)来解决此问题。

public class SampleController : Controller
{
    public ActionResult IndexA(string id)
    {

        return View("Index");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult IndexA()
    {
        return RedirectToRoute("routeA", new { action = "Confirmation" });
    }

    public ActionResult Confirmation()
    {
        return View("Confirmation");
    }

    public ActionResult IndexB(string id)
    {
        return View("Index");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult IndexB()
    {
        // Note that changing this one to RedirectToRoute is not strictly
        // necessary, but may be more clear to future analysis of the configuration.
        return RedirectToRoute("routeB", new { action = "Confirmation" });
    }
}