web-dev-qa-db-fra.com

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 est réussie. Comportement standard après échafaudage MVC.

J'essaie de changer cette méthode d'édition pour rediriger vers la page précédente (pas d'index). Comme ma méthode Edit n'utilisait 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 ici que les roues sont tombées. Je ne pouvais pas obtenir l'URL analysée à partir du paramètre id correctement.

*** MISE À JOUR: RESOLU ** *

En utilisant l'exemple de Garry comme guide, j'ai changé mon paramètre de "id" en "returnUrl" et ai utilisé un champ caché pour transmettre mon paramètre (au lieu de la balise de formulaire). Leçon apprise: utilisez uniquement le paramètre "id" de la manière dont il était destiné et maintenez-le simple. Ça fonctionne maintenant. Voici mon code mis à jour avec des notes:

Tout d'abord, je récupère l'URL précédente à l'aide de Request.UrlReferrer, comme je l'ai fait pour 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] à l'aide d'un champ masqué de la forme:

@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 y redirigeons ....

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

Je suppose (corrigez-moi si je me trompe) que vous souhaitez afficher de nouveau la page de modification en cas d'échec de la modification. Pour ce faire, vous utilisez une redirection.

Vous pouvez avoir plus de chance en retournant simplement la vue plutôt qu'en essayant de rediriger l'utilisateur, de cette façon vous pourrez utiliser le ModelState pour générer des erreurs.

Edit:

Mis à jour en fonction des commentaires. Vous pouvez placer l'URL précédente dans viewModel, l'ajouter à un champ masqué, 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 pour votre vue n'a pas besoin d'utiliser cette URL de retour non plus, vous devriez pouvoir vous en tirer avec:

@model ViewModel

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

Pour revenir à l'affichage de votre action de formulaire sur une URL incorrecte, c'est parce que vous transmettez une URL en tant que paramètre 'id'. Le routage formate automatiquement votre URL avec le chemin de retour.

Cela ne fonctionnera pas car votre formulaire sera envoyé à une action du contrôleur qui ne saura pas comment enregistrer les modifications. Vous devez d’abord publier votre action de sauvegarde, puis gérer la redirection qu’elle contient.

53
Garry Marsland