75 votes

C# ASP.NET MVC Retour à la page précédente

J'ai une méthode d'édition de base dans mon contrôleur qui redirige vers une liste de niveau supérieur ("Index") lorsque l'édition réussit. Comportement standard après l'échafaudage MVC.

J'essaie de modifier cette méthode d'édition pour qu'elle redirige vers la page précédente (et non vers l'index). Comme ma méthode d'édition n'utilise pas le paramètre d'entrée mappé par défaut "id", j'ai d'abord essayé de l'utiliser pour transmettre l'URL précédente.

Dans ma méthode Edit "get", j'ai utilisé cette ligne pour récupérer l'URL précédente et cela a bien fonctionné :

ViewBag.ReturnUrl = Request.UrlReferrer;

J'ai ensuite envoyé cette URL de retour à la méthode Edit "post" en utilisant ma balise de formulaire comme ceci :

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

C'est maintenant que les roues tombent. Je n'ai pas réussi à analyser l'URL du paramètre id correctement.

*** MISE À JOUR : RÉSOLU ** *

En utilisant l'exemple de Garry comme guide, j'ai changé mon paramètre de "id" à "returnUrl" et j'ai utilisé un champ caché pour passer mon paramètre (au lieu de la balise de formulaire). Leçon apprise : N'utilisez le paramètre "id" que de la manière dont il est censé être utilisé et restez simple. Cela fonctionne maintenant. Voici mon code mis à jour avec des notes :

Tout d'abord, je récupère l'URL précédente en utilisant Request.UrlReferrer comme je l'ai fait la première fois.

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

et je passe maintenant le paramètre returnUrl du modèle à la méthode [HttpPost] en utilisant un champ caché dans le formulaire :

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

Dans la méthode [HttpPost], nous extrayons le paramètre du champ caché et nous le redirigeons vers .....

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

Même si vous n'utilisez pas id Je ne l'utiliserais pas pour passer une URL. Cela ressemble à un hack, et je suis sûr qu'il y a une meilleure façon de le faire.

0 votes

Oui, Eirc, vous avez raison. J'utilisais un affreux hack. C'est ma première application MVC. J'ai essayé beaucoup de choses et lu beaucoup de messages et le hack était ma meilleure tentative. Je l'ai corrigé en me basant sur l'exemple de Gary. Merci,

64voto

GarryM Points 424

Je suppose (corrigez-moi si je me trompe) que vous voulez réafficher la page d'édition si l'édition échoue et que pour ce faire, vous utilisez une redirection.

Vous aurez peut-être plus de chance en renvoyant simplement la vue plutôt qu'en essayant de rediriger l'utilisateur, de cette façon vous pourrez utiliser le ModelState pour afficher les erreurs éventuelles.

Edit :

Mise à jour basée sur les commentaires. Vous pouvez placer l'URL précédente dans le viewModel, l'ajouter à un champ caché puis l'utiliser à nouveau dans l'action qui enregistre les modifications.

Par exemple :

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

La méthode BeginForm de votre vue n'a pas besoin d'utiliser cette URL de retour non plus, vous devriez pouvoir vous en passer :

@model ViewModel

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

Pour en revenir à l'action de votre formulaire qui renvoie à une URL incorrecte, c'est parce que vous passez une URL comme paramètre "id", donc le routage formate automatiquement votre URL avec le chemin de retour.

Cela ne fonctionnera pas car votre formulaire sera envoyé à une action de contrôleur qui ne saura pas comment enregistrer les modifications. Vous devez d'abord envoyer le formulaire à votre action de sauvegarde, puis gérer la redirection dans cette action.

0 votes

Oui, mais j'ai besoin qu'il redirige vers la page précédente si la modification réussit. Je pense que cela ne fonctionnait pas parce que j'utilisais "id". J'ai changé le paramètre en "url" comme indiqué ci-dessous et cela semble avoir fonctionné lors de ma première tentative mais je dois le tester plus.... sur et je posterai ce que j'ai. C'est la première fois que je poste sur ce site et il me faut un peu de temps pour m'y habituer.

0 votes

Dans ce cas, vous pouvez placer l'URL précédente dans le ViewBag lors du chargement initial de la page d'édition, puis la placer dans un champ caché. Vous pouvez ensuite y accéder en tant que partie de votre ViewModel dans l'action post et la rediriger vers celle-ci. Je préférerais quelque chose comme ça plutôt que de l'envoyer via une chaîne de requête. Si vous souhaitez un exemple, faites-le moi savoir.

0 votes

Voir, la clause if(success) de Garry. Ici vous pouvez rediriger vers n'importe quelle page que vous désirez. Aka retour à la page précédente. redirectToAction peut également prendre des paramètres, des variables de contrôleur-action.

4voto

Mohamed Elamin Points 185

Pour ASP.NET Core Vous pouvez utiliser l'attribut asp-route-* :

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

Un exemple : Imaginez que vous avez un contrôleur de véhicule avec des actions

Index

Détails

Modifier

et vous pouvez modifier n'importe quel véhicule à partir de l'index ou des détails, donc si vous avez cliqué sur modifier à partir de l'index, vous devez retourner à l'index après la modification. et si vous avez cliqué sur modifier à partir des détails, vous devez retourner aux détails après la modification.

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

Dans votre contrôleur :

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

4voto

NateM Points 1

Je sais que c'est très tard, mais peut-être que cela aidera quelqu'un d'autre.

J'utilise un bouton Annuler pour revenir à l'url de référence. Dans la vue, essayez d'ajouter ceci :

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

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

Ensuite, vous pouvez configurer vos boutons href comme ceci :

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

A part ça, la mise à jour de Jason Enochs fonctionne très bien !

0voto

Clark Kent Points 5845

Voici une autre option que vous pouvez appliquer pour ASP NET MVC.

Normalement, vous devriez utiliser BaseController pour chaque Controller classe.

Donc à l'intérieur de c'est Constructeur font ce qui suit.

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

Et maintenant dans ANY voir vous pouvez faire comme

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

Profitez-en !

1 votes

Je n'ai pas encore essayé, mais j'aime bien ce que ça donne. Si cela fonctionne, je pense que c'est mieux que l'exemple que j'ai posté il y a plusieurs années. Je l'essaierais bien maintenant, mais je suis plongé dans Python sur une machine Linux. Merci d'avoir partagé cette expérience.

0 votes

Que se passe-t-il si l'utilisateur visite directement la page web ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X