web-dev-qa-db-fra.com

MVC - Transmission de données avec RedirectToAction ()

Je voudrais prendre les données saisies dans un formulaire utilisateur MVC et les afficher dans une vue différente.

La classe a la variable privée suivante:

IList<string> _pagecontent = new List<string>();

L'action suivante accepte un objet FormCollection, le valide et le transmet à la vue "Aperçu" en tant que liste:

[Authorize(Roles = "Admins")]
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateContent(FormCollection collection)
{
    if (ModelState.IsValid)
    {
        string PageToInsert = collection["PageToInsert"];
        string PageHeader = collection["PageHeader"];
        string PageBody = collection["PageBody"];

        //validate, excluded...

        _pagecontent.Add(PageToInsert);
        _pagecontent.Add(PageHeader);
        _pagecontent.Add(PageBody);

    }
    return RedirectToAction("Preview", _pagecontent);
}

La vue Aperçu a la directive de page suivante pour passer une liste d'objets fortement typée:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Template.Master" Inherits="System.Web.Mvc.ViewPage<List<string>>" %>

Je m'attendrais à pouvoir utiliser l'objet Model pour obtenir mes données, mais hélas je ne peux pas. À la ligne suivante, j'obtiens un error index out of bounds exception, indiquant que l'index doit être non négatif et inférieur à la taille de la collection:

<% if (Model[0].ToString() == "0") { %>

Et certains paramètres étranges ont été ajoutés à l'URL, car il se résout en http://localhost:1894/Admin/Preview?Capacity=4&Count=3

J'ai donc deux questions:

  1. Lorsque j'appelle RedirectToAction et que je lui passe ma liste, pourquoi est-il inaccessible dans l'objet Model de la vue?
  2. Quelle est la bonne façon de faire ce que j'essaie de faire, à savoir passer une collection de chaînes à une vue pour y être affichée?
59
splatto

Essayez d'utiliser TempData. C'est comme un objet de session à un coup. Vous mettez des valeurs que vous voulez dans TempData, redirigez immédiatement et sortez-les. Il y a un bon résumé ici: http://blogs.teamb.com/craigstuntz/2009/01/23/37947/

55
MichaelGG

Soyez prudent lorsque vous utilisez TempData. Cela fonctionne très bien dans un environnement à serveur unique, mais dans un environnement cloud, il peut ne pas fonctionner comme prévu car vous ne pouvez pas garantir que la demande atteindra la même machine. Cela se produit car TempData s'appuie sur la session asp.net. Mais si vous utilisez un autre gestionnaire de session comme SQL ou AppFabric Cache, cela fonctionnera bien.

11
João Miguel

Le deuxième paramètre de RedirectAction est routeValues, pas model.

protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues);

Essayez d'utiliser TempData pour le modèle. Son pour les données persistantes entre les redirections.

7
AndreasN

Le problème avec RedirectToAction est qu'il renvoie un HTTP 302 et que le navigateur est alors en train de faire sa propre requête HTTP. Vous pouvez envisager d'utiliser un cookie et/ou un objet de session pour conserver les données entre les demandes.

4
Chad Moran

Cela ne fonctionne pas car RedirectToAction renvoie en fait un Http 302 au navigateur. Lorsque le navigateur reçoit ce 302, il fait une nouvelle demande au serveur demandant la nouvelle page. Nouvelle requête, nouvelles variables temporaires.

Vous rencontrerez également ce problème lorsque vous essayez d'enregistrer/modifier/supprimer quelque chose et pour une raison quelconque, vous le refusez et vous devez renvoyer l'ancien formulaire.

Donc, au lieu de:

return RedirectToAction("Preview", _pagecontent);

Mettez la logique de prévisualisation dans une méthode distincte et appelez-la simplement:

return PreviewLogic(_pagecontent);

Vous pouvez également utiliser le dic TempData [] pour conserver les données pour la prochaine demande comme d'autres l'ont dit, mais vous n'éviterez pas les 302 aller-retour supplémentaires vers le serveur.

3
andrecarlucci

On dirait que vous essayez de faire:

public ActionResult UpdateContent(FormCollection form) {
    ...
    return View("Preview", _pagecontent);
}

Notez qu'une redirection est censée être une "table rase" pour le navigateur (sauf pour des choses comme le cookie d'authentification). Vous ne pouvez pas dire au navigateur de transmettre des informations à la prochaine demande, car la prochaine demande devrait être autonome. Tout ce que vous avez à faire est d'indiquer au navigateur l'URL à demander ensuite. Dans ASP.NET MVC, lorsque vous passez un objet-arguments à RedirectToAction, les propriétés publiques de cet objet sont ajoutées en tant que paramètres de chaîne de requête à l'URL générée.

2
yfeldblum

Ne pouvez-vous pas simplement faire 2 résultats d'action avec le même nom et en marquer 1 avec HttpPost?

    public ActionResult UpdateContent(FormCollection preview = null)
    {
        return View(preview);
    }
    [HttpPost]
    public ActionResult UpdateContent(FormCollection collection = null, bool preview = false)
    {
        if (preview)
            return UpdateContent(collection);
        else
            return UpdateContent(null);
    }
0
TeamEASI.com