C# ASP.NET MVC Return to Previous Page
I am assuming (please correct me if I am wrong) that you want to re-display the edit page if the edit fails and to do this you are using a redirect.
You may have more luck by just returning the view again rather than trying to redirect the user, this way you will be able to use the ModelState to output any errors too.
Edit:
Updated based on feedback. You can place the previous URL in the viewModel, add it to a hidden field then use it again in the action that saves the edits.
For instance:
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);
}
}
The BeginForm method for your view doesn't need to use this return URL either, you should be able to get away with:
@model ViewModel
@using (Html.BeginForm())
{
...
<input type="hidden" name="PreviousUrl" value="@Model.PreviousUrl" />
}
Going back to your form action posting to an incorrect URL, this is because you are passing a URL as the 'id' parameter, so the routing automatically formats your URL with the return path.
This won't work because your form will be posting to an controller action that won't know how to save the edits. You need to post to your save action first, then handle the redirect within it.
For ASP.NET Core You can use asp-route-* attribute:
<form asp-action="Login" asp-route-previous="@Model.ReturnUrl">
An example: Imagine that you have a Vehicle Controller with actions
Index
Details
Edit
and you can edit any vehicle from Index or from Details, so if you clicked edit from index you must return to index after edit and if you clicked edit from details you must return to details after edit.
//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>
In your controller:
// 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);
}
I know this is very late, but maybe this will help someone else.
I use a Cancel button to return to the referring url. In the View, try adding this:
@{
ViewBag.Title = "Page title";
Layout = "~/Views/Shared/_Layout.cshtml";
if (Request.UrlReferrer != null)
{
string returnURL = Request.UrlReferrer.ToString();
ViewBag.ReturnURL = returnURL;
}
}
Then you can set your buttons href like this:
<a href="@ViewBag.ReturnURL" class="btn btn-danger">Cancel</a>
Other than that, the update by Jason Enochs works great!