C # ASP.NET MVC Zurück zur vorherigen Seite

74

Ich habe eine grundlegende Bearbeitungsmethode in meinem Controller, die nach erfolgreicher Bearbeitung zu einer Liste der obersten Ebene („Index“) zurückleitet. Standardverhalten nach MVC-Gerüsten.

Ich versuche, diese Bearbeitungsmethode zu ändern, um zur vorherigen Seite (nicht zum Index) zurückzukehren. Da meine Edit-Methode nicht den standardmäßig zugeordneten Eingabeparameter "id" verwendete, habe ich zuerst versucht, damit die vorherige URL zu übergeben.

Bei meiner Edit-Methode "get" habe ich diese Zeile verwendet, um die vorherige URL abzurufen, und es hat einwandfrei funktioniert:

ViewBag.ReturnUrl = Request.UrlReferrer;

Ich habe diese Rückgabe-URL dann mithilfe meines Formular-Tags wie folgt an die Methode "Post" bearbeiten gesendet:

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

Hier fielen die Räder ab. Ich konnte die URL vom ID-Parameter nicht richtig analysieren.

***. UPDATE: Gelöst ** *

Am Beispiel von Garry habe ich meinen Parameter von "id" in "returnUrl" geändert und ein verstecktes Feld verwendet, um meinen Parameter zu übergeben (anstelle des Formular-Tags). Lektion gelernt: Verwenden Sie den Parameter "id" nur so, wie er verwendet werden sollte, und halten Sie ihn einfach. Es funktioniert jetzt. Hier ist mein aktualisierter Code mit Notizen:

Zuerst greife ich mit Request.UrlReferrer wie beim ersten Mal auf die vorherige URL zurück.

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

und ich übergebe jetzt den Parameter returnUrl vom Modell an die Methode [HttpPost] unter Verwendung eines ausgeblendeten Feldes in der Form:

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

In der [HttpPost] -Methode ziehen wir den Parameter aus dem ausgeblendeten Feld und leiten ihn dorthin weiter ....

    //
    // 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);
    }
Jason Enochs
quelle
1
Selbst wenn Sie nicht verwenden id, würde ich es nicht verwenden, um eine URL zu übergeben. Das scheint ein Hack zu sein, und ich bin sicher, es gibt einen besseren Weg, dies zu tun.
Eric Andres
Ja, Eirc, du bist richtig. Ich habe einen hässlichen Hack benutzt. Dies ist meine erste MVC-App. Ich habe viele Dinge ausprobiert und viele Beiträge gelesen und der Hack war mein bester Versuch. Ich habe es anhand von Garys Beispiel behoben. Vielen Dank,
Jason Enochs

Antworten:

63

Ich gehe davon aus (bitte korrigieren Sie mich, wenn ich falsch liege), dass Sie die Bearbeitungsseite erneut anzeigen möchten, wenn die Bearbeitung fehlschlägt, und verwenden Sie dazu eine Umleitung.

Möglicherweise haben Sie mehr Glück, wenn Sie die Ansicht erneut zurückgeben, anstatt zu versuchen, den Benutzer umzuleiten. Auf diese Weise können Sie den ModelState auch zur Ausgabe von Fehlern verwenden.

Bearbeiten:

Aktualisiert basierend auf Feedback. Sie können die vorherige URL in das viewModel einfügen, sie einem ausgeblendeten Feld hinzufügen und sie dann erneut in der Aktion verwenden, in der die Änderungen gespeichert werden.

Zum Beispiel:

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

Die BeginForm-Methode für Ihre Ansicht muss diese Rückgabe-URL ebenfalls nicht verwenden. Sie sollten in der Lage sein, Folgendes zu erreichen:

@model ViewModel

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

Wenn Sie zu Ihrer Formularaktion zurückkehren und eine falsche URL veröffentlichen, übergeben Sie eine URL als Parameter 'id', sodass das Routing Ihre URL automatisch mit dem Rückgabepfad formatiert.

Dies funktioniert nicht, da Ihr Formular an eine Controller-Aktion gesendet wird, die nicht weiß, wie die Änderungen gespeichert werden sollen. Sie müssen zuerst in Ihrer Speicheraktion posten und dann die darin enthaltene Umleitung durchführen.

Garry Marsland
quelle
Ja, aber ich brauche es, um zur vorherigen Seite zurückzukehren, wenn die Bearbeitung erfolgreich ist. Ich denke, dass es nicht funktioniert hat, weil ich "id" verwendet habe. Ich habe den Parameter wie unten gezeigt in "url" geändert und es scheint bei meinem ersten Versuch funktioniert zu haben, aber ich muss ihn mehr testen ... warte und ich werde posten, was ich habe. Ich bin neu darin, auf dieser Seite zu posten und mich daran zu gewöhnen.
Jason Enochs
In diesem Fall können Sie die vorherige URL beim ersten Laden der Seite "Bearbeiten" in der Ansichtsleiste platzieren und dann in einem ausgeblendeten Feld platzieren. Anschließend können Sie als Teil Ihres ViewModels in der Post-Aktion darauf zugreifen und darauf umleiten. Ich würde so etwas vorziehen, als es per Querystring zu senden. Wenn Sie ein Beispiel möchten, lassen Sie es mich wissen.
Garry Marsland
siehe Garrys if (Erfolgs-) Klausel. Hier können Sie zu einer beliebigen Seite weiterleiten. Aka zurück zur vorherigen Seite. redirectToActionkann auch Parameter, Controller-Action-Variablen nehmen.
IAmGroot
Ok, Gary. Warte ein paar Minuten. Ich versuche deine Technik. Mein letzter Versuch scheint zu funktionieren, aber dein Versuch scheint eher der richtige zu sein ... Ich mache drei Dinge gleichzeitig, also werde ich ein paar Minuten brauchen.
Jason Enochs
1
Ich denke, hier ist ein kleiner Fehler im Code. Anstatt Folgendes zu verwenden: "return RedirectToAction (viewModel.PreviousUrl);" Sie sollten Folgendes verwenden: "return Redirect (viewModel.PreviousUrl);"
AidanO
4

Für ASP.NET Core Sie können das Attribut asp-route- * verwenden:

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

Ein Beispiel: Stellen Sie sich vor, Sie haben einen Fahrzeugcontroller mit Aktionen

Index

Einzelheiten

Bearbeiten

und Sie können jedes Fahrzeug über den Index oder über Details bearbeiten. Wenn Sie also auf Bearbeiten aus Index klicken, müssen Sie nach der Bearbeitung zum Index zurückkehren. Wenn Sie auf Details bearbeiten klicken, müssen Sie nach der Bearbeitung zu den Details zurückkehren.

//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 Ihrem 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);
    }
Mohamed Elamin
quelle
1

Ich weiß, dass dies sehr spät ist, aber vielleicht hilft das jemand anderem.

Ich benutze eine Schaltfläche Abbrechen, um zur verweisenden URL zurückzukehren. Versuchen Sie in der Ansicht Folgendes hinzuzufügen:

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

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

Dann können Sie Ihre Schaltflächen wie folgt einstellen:

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

Davon abgesehen funktioniert das Update von Jason Enochs hervorragend!

NateM
quelle
0

Hier ist nur eine weitere Option, die Sie für ASP NET MVC anwenden können.

Normalerweise sollten Sie BaseControllerfür jede ControllerKlasse eine Klasse verwenden.

Gehen Sie also innerhalb der Konstruktormethode wie folgt vor.

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

Und jetzt in jeder Ansicht, die Sie mögen können

<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>

Genießen!

DmitryBoyko
quelle
1
Ich habe das noch nicht ausprobiert, aber ich mag es, wie es aussieht. Wenn dies funktioniert, denke ich, ist es besser als das Beispiel, das ich vor einigen Jahren gepostet habe. Ich würde das jetzt versuchen, aber ich bin tief in Python auf einer Linux-Box. Vielen Dank für das Teilen.
Jason Enochs
Was passiert, wenn der Benutzer die Webseite direkt besucht?
Tomas