C#ASP.NET MVC返回上一页


74

我的控制器中有一个基本的Edit方法,当编辑成功时,该方法会重定向回到顶级列表(“索引”)。MVC脚手架后的标准行为。

我正在尝试更改此Edit方法以重定向回上一页(而不是索引)。由于我的Edit方法未使用默认的映射输入参数“ id”,因此我首先尝试使用该参数来传递先前的URL。

在我的“获取”方法中,我使用了这一行来获取先前的URL,并且效果很好:

ViewBag.ReturnUrl = Request.UrlReferrer;

然后,我使用如下形式的表单标签将此返回URL发送给Edit“ post”方法:

@using (Html.BeginForm(new { id = ViewBag.ReturnUrl }))

现在这是车轮掉下来的地方。我无法从id参数正确解析网址。

*** 更新:已解决 ** *

以Garry的示例为指导,我将参数从“ id”更改为“ returnUrl”,并使用了一个隐藏字段来传递我的参数(而不是form标签)。经验教训:仅使用“ id”参数,并使其保持简单。现在可以使用了。这是我更新的代码,并带有注释:

首先,与第一次一样,我使用Request.UrlReferrer捕获了先前的URL。

    //
    // GET: /Question/Edit/5

    public ActionResult Edit(int id)
    {
        Question question = db.Questions.Find(id);
        ViewBag.DomainId = new SelectList(db.Domains, "DomainId", "Name", question.DomainId);
        ViewBag.Answers = db.Questions
                            .AsEnumerable()
                            .Select(d => new SelectListItem
                            {
                                Text = d.Text,
                                Value = d.QuestionId.ToString(),
                                Selected = question.QuestionId == d.QuestionId
                            });
        // Grab the previous URL and add it to the Model using ViewData or ViewBag
        ViewBag.returnUrl = Request.UrlReferrer;
        ViewBag.ExamId = db.Domains.Find(question.DomainId).ExamId;
        ViewBag.IndexByQuestion = string.Format("IndexByQuestion/{0}", question.QuestionId);
        return View(question);
    }

现在,我使用以下形式的隐藏字段将模型的returnUrl参数传递给[HttpPost]方法:

@using (Html.BeginForm())
{
    <input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" />
    ...

在[HttpPost]方法中,我们从隐藏字段中提取参数并重定向到它。

    //
    // POST: /Question/Edit/5

    [HttpPost]
    public ActionResult Edit(Question question, string returnUrl) // Add parameter
    {
        int ExamId = db.Domains.Find(question.DomainId).ExamId;
        if (ModelState.IsValid)
        {
            db.Entry(question).State = EntityState.Modified;
            db.SaveChanges();
            //return RedirectToAction("Index");
            return Redirect(returnUrl);
        }
        ViewBag.DomainId = new SelectList(db.Domains, "DomainId", "Name", question.DomainId);
        return View(question);
    }

1
即使您没有使用id,我也不会使用它来传递URL。这似乎是一种破解,而且我敢肯定有更好的方法来做到这一点。
埃里克·安德列斯

是的,Eirc,您是对的。我当时使用的是丑陋的骇客。这是我的第一个MVC应用程序。我尝试了许多事情,读了许多文章,而骇客入侵是我的最佳尝试。我根据加里的例子修复了它。谢谢,
Jason Enochs 2012年

Answers:


63

我假设(如果我错了,请纠正我)如果编辑失败,您想重新显示编辑页面,为此,您正在使用重定向。

通过再次返回视图而不是尝试重定向用户,您可能会有更多的运气,这样您就可以使用ModelState输出任何错误。

编辑:

根据反馈进行了更新。您可以将先前的URL放置在viewModel中,将其添加到隐藏字段中,然后在保存编辑的操作中再次使用它。

例如:

public ActionResult Index()
{
    return View();
}

[HttpGet] // This isn't required
public ActionResult Edit(int id)
{
   // load object and return in view
   ViewModel viewModel = Load(id);

   // get the previous url and store it with view model
   viewModel.PreviousUrl = System.Web.HttpContext.Current.Request.UrlReferrer;

   return View(viewModel);
}

[HttpPost]
public ActionResult Edit(ViewModel viewModel)
{
   // Attempt to save the posted object if it works, return index if not return the Edit view again

   bool success = Save(viewModel);
   if (success)
   {
       return Redirect(viewModel.PreviousUrl);
   }
   else
   {
      ModelState.AddModelError("There was an error");
      return View(viewModel);
   }
}

用于视图的BeginForm方法也不需要使用此返回URL,您应该可以摆脱:

@model ViewModel

@using (Html.BeginForm())
{
    ...
    <input type="hidden" name="PreviousUrl" value="@Model.PreviousUrl" />
}

回到表单操作中,发布到错误的URL,这是因为您将URL作为'id'参数传递,因此路由会自动使用返回路径设置URL的格式。

这将不起作用,因为您的表单将被发布到将不知道如何保存编辑内容的控制器操作中。您需要先发布到保存操作,然后再处理其中的重定向。


是的,但是如果编辑成功,我需要它重定向到上一页。我认为它不起作用,因为我使用的是“ id”。我将参数更改为“ url”,如下所示,它似乎已经在我的第一次尝试中起作用,但是我需要对其进行更多的测试....等等,我将发布我所拥有的。我是刚开始在这个网站上发帖并抽搐以适应它。
杰森·埃诺克斯

在这种情况下,您可以在最初加载“编辑”页面时将先前的URL放置在ViewBag中,然后将其放置在隐藏字段中。然后,您可以在后期操作中将其作为ViewModel的一部分进行访问,并重定向到它。我更喜欢这样的事情,而不是通过querystring发送。如果您想举个例子,请告诉我。
Garry Marsland 2012年

参见Garry的if(success)子句。在这里,您可以重定向到所需的任何页面。又回到上一页。 redirectToAction也可以采用参数,即控制器动作变量。
IAmGroot 2012年

好吧,加里 等一下 我正在尝试你的技术。我的最后一次尝试似乎有效,但是您的尝试看起来更像是正确的方法...我一次要做三件事,所以这需要我几分钟。
杰森·埃诺克斯

1
我认为这里的代码中有一个小错误。而不是使用:“ return RedirectToAction(viewModel.PreviousUrl);” 您应该使用:“ return Redirect(viewModel.PreviousUrl);”
AidanO

4

对于ASP.NET Core, 可以使用asp-route- *属性:

<form asp-action="Login" asp-route-previous="@Model.ReturnUrl">

示例: 假设您有一个带动作的车辆控制器

指数

细节

编辑

并且您可以从“索引”或“详细信息”编辑任何车辆,因此,如果您单击“从索引编辑”,则必须在编辑后返回索引;如果您单击“从细节编辑”,则必须在编辑后返回细节。

//In your viewmodel add the ReturnUrl Property
public class VehicleViewModel
{
     ..............
     ..............
     public string ReturnUrl {get;set;}
}



Details.cshtml
<a asp-action="Edit" asp-route-previous="Details" asp-route-id="@Model.CarId">Edit</a>

Index.cshtml
<a asp-action="Edit" asp-route-previous="Index" asp-route-id="@item.CarId">Edit</a>

Edit.cshtml
<form asp-action="Edit" asp-route-previous="@Model.ReturnUrl" class="form-horizontal">
        <div class="box-footer">
            <a asp-action="@Model.ReturnUrl" class="btn btn-default">Back to List</a>
            <button type="submit" value="Save" class="btn btn-warning pull-right">Save</button>
        </div>
    </form>

在您的控制器中:

// GET: Vehicle/Edit/5
    public ActionResult Edit(int id,string previous)
    {
            var model = this.UnitOfWork.CarsRepository.GetAllByCarId(id).FirstOrDefault();
            var viewModel = this.Mapper.Map<VehicleViewModel>(model);//if you using automapper
    //or by this code if you are not use automapper
    var viewModel = new VehicleViewModel();

    if (!string.IsNullOrWhiteSpace(previous)
                viewModel.ReturnUrl = previous;
            else
                viewModel.ReturnUrl = "Index";
            return View(viewModel);
        }



[HttpPost]
    public IActionResult Edit(VehicleViewModel model, string previous)
    {
            if (!string.IsNullOrWhiteSpace(previous))
                model.ReturnUrl = previous;
            else
                model.ReturnUrl = "Index";
            ............. 
            .............
            return RedirectToAction(model.ReturnUrl);
    }

2

我知道这已经很晚了,但这也许会对其他人有所帮助。

我使用“取消”按钮返回引荐网址。在视图中,尝试添加以下内容:

@{
  ViewBag.Title = "Page title";
  Layout = "~/Views/Shared/_Layout.cshtml";

  if (Request.UrlReferrer != null)
  {
    string returnURL = Request.UrlReferrer.ToString();
    ViewBag.ReturnURL = returnURL;
  }
}

然后,您可以像这样设置按钮href:

<a href="@ViewBag.ReturnURL" class="btn btn-danger">Cancel</a>

除此之外,Jason Enochs的更新效果很好!


0

您可以选择这是ASP NET MVC的另一个选择。

通常你应该BaseController为每个使用类Controller班级班级。

因此,在其构造方法内部进行以下操作。

public class BaseController : Controller
{
        public BaseController()
        {
            // get the previous url and store it with view model
            ViewBag.PreviousUrl = System.Web.HttpContext.Current.Request.UrlReferrer;
        }
}

现在,在任何视图中,您都可以像

<button class="btn btn-success mr-auto" onclick="  window.location.href = '@ViewBag.PreviousUrl'; " style="width:2.5em;"><i class="fa fa-angle-left"></i></button>

请享用!


1
我还没有尝试过,但是我肯定喜欢它的外观。如果这行得通,那么我认为它比我几年前发布的示例更好。我现在尝试一下,但是在Linux平台上我深陷Python。感谢您分享这个。
詹森·埃诺克斯

如果用户直接访问网页会怎样?
托马斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.