【问题标题】:MVC route not kept on RedirectToActionMVC 路由未保留在 RedirectToAction 上
【发布时间】:2017-07-04 05:23:33
【问题描述】:

我有这个路由配置:

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

我的 Sample 控制器包含这些 Action 方法:

 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 页面?

谢谢。

【问题讨论】:

  • 向我们展示视图Index
  • 查看索引可以在下面找到:@{ ViewBag.Title = "Index";布局 = "~/Views/Shared/_Layout.cshtml"; }

    索引

    @Html.Partial("OrderForm")
  • OrderForm: using (Html.BeginForm("IndexB", "Sample", new { @id = "OrderForm" })) { @Html.AntiForgeryToken() }
  • 是的,这解决了这种情况,但我希望它能够以两种方式工作。如果我键入 RouteB 并进行 POST,在这种情况下它将转到 RouteA/Confirmation。我想一直保持相同的路线,不管是哪一条。

标签: c# asp.net asp.net-mvc asp.net-mvc-routing


【解决方案1】:

这里有两个问题。正如其他人所指出的,您的 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" });
    }
}

【讨论】:

  • 感谢 NighOwl888,这已经解决了这个问题。这将帮助我避免创建 7 个不同的控制器来显示相似的视图 :)
【解决方案2】:

你的问题很简单。 看看你的控制器,IndexA 和 IndexB 方法返回相同的视图; (来自你的 cmets)

@{ 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> 
}

当你点击提交时,你总是向IndexB发帖

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

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

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

【讨论】:

  • 如果我改为使用 (Html.BeginForm("IndexA", "Sample", new { @id = "OrderForm" })) 页面仍然重定向到 RouteB/Confirmation,也会发生同样的情况。有没有办法保持相同的索引视图?
【解决方案3】:

问题在于您的routeArouteB 路由都可以为SampleController 中的IndexA 操作创建链接。因此,BeginForm 只会短路并选择第一条可行的路线,这可能是也可能不是您正在寻找的“正确”路线。要区分路由,请通过路由名称生成它们:

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

但是,这只会让您获得“默认”routeA 路由,即/routeA/。除了路由的默认操作之外,没有其他方法可以指定其他操作。

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

除此之外,您还需要以某种方式区分这两个路由,这样在生成 URL 时应该使用哪个路由就不会模棱两可了。使用标准路由通常很难做到这一点,这就是为什么属性路由是更好的方法,如果您要摆脱对所有事情的简单使用默认路由。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-05
    • 2010-10-07
    • 2011-06-06
    • 2010-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多