2009-11-28 7 views
0

Je suis nouveau sur ASP.NET MVC. Après avoir longtemps travaillé avec le modèle ASP.NET traditionnel, il me faut du temps pour comprendre ce modèle. Je passe par NerdDinner pour comprendre comment les choses fonctionnent. Donc, j'ai un objet qui doit être passé à travers deux vues. Semblable à l'article NerdDinner Step 6: ViewData and ViewModel.Passage de données du contrôleur à la vue, retour au contrôleur, retour à la vue

Je conserve les données de Get to Post pour la première fois, puis je le place dans TempData et le passe à une autre action (AnotherAction). Une fois que je reçois mes données sur Get, je ne peux pas les conserver sur Post.

Voici mon code:

public class DinnerFormViewModel 
{ 
    public Dinner Dinner { get; private set; } 

    public DinnerFormViewModel(Dinner dinner) 
    { 
     Dinner = dinner; 
    } 
} 

public class DinnersController : Controller 
{ 
    public ActionResult Action() 
    { 
     Dinner dinner = new Dinner(); 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Action(Dinner dinner, FormCollection collection) 
    { 
     try 
     { 
      // Some code 
      TempData["Dinner"] = dinner; 
      return RedirectToAction("AnotherAction"); 
     } 
     catch 
     { 
      return View(); 
     } 
    } 

    public ActionResult AnotherAction() 
    { 
     Dinner dinner = (Dinner)TempData["Dinner"]; // Got my dinner object 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult AnotherAction(Dinner dinner, FormCollection collection) 
    { 
     // Lost my dinner object, dinner comes in as null 
    } 
} 

Répondre

1

Selon ce blog post TempData est seulement disponible pour une seule requête après son ensemble.

Voici une citation du message:

Si vous définissez TempData et votre action renvoie alors un ViewResult, la demande suivante, quoi qu'il arrive à être (une requête AJAX, une autre page que l'utilisateur a ouvert dans un onglet différent, etc.), va voir la valeur TempData que vous définissez, et aucune autre requête ne le verra.

Donc, étant donné le code que je vois, vous pouvez obtenir le dîner TempData le get de AnotherAction qui est la première demande après avoir défini sur Action. Cependant en regardant le code et ne pas voir le code pour voir AnotherAction il n'est pas clair comment vous passez les données à la poste pour AnotherAction. L'instance de dîner ne sera pas dans TempData pour cette requête car c'est la deuxième requête après que vous l'avez définie dans TempData.Et si vous n'avez pas les balises de formulaire appropriées définies sur la vue AntoherAction, le cadre n'aura pas les valeurs de formulaire appropriées pour instancier un objet dîner dans le message.

Donc, soit vous devrez réinitialiser TempData avec l'instance de dîner, il le premier AnotherAction appel, puis récupérer le dîner sur TempData dans le poste AnotherAction, ou vous pouvez suivre les conseils de dm et utiliser des champs cachés dans votre vue . IMO, vous devriez utiliser la méthode DM pour cela et éviter d'utiliser TempData.

Modifier Ajout d'un exemple de réinitialisation de TempData dans AnotherAction pour y accéder par la poste.

Modèle:

public class Dinner 
    { 
    public string Name{get;set;} 
    } 

    public class DinnerFormViewModel 
    { 
    public Dinner Dinner {get;private set;} 

    public DinnerFormViewModel(Dinner dinner) 
    { 
     Dinner = dinner; 
    } 
    } 

Controller:

public class DinnersController : Controller 
    { 
    public ActionResult Action() 
    { 
     Dinner dinner = new Dinner(); 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Action(Dinner dinner, FormCollection collection) 
    { 
     try 
     { 
     // Some code 
     TempData[ "Dinner" ] = dinner; 
     return RedirectToAction("AnotherAction"); 
     } 
     catch 
     { 
     return View(); 
     } 
    } 

    public ActionResult AnotherAction() 
    { 
     Dinner dinner = (Dinner)TempData[ "Dinner" ]; // Got my dinner object 
     TempData[ "Dinner" ] = dinner; // Reset the dinner object in temp data 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult AnotherAction(Dinner dinnerFromPostedFormValues, FormCollection collection) 
    { 
     //dinnerFromPostedFormValues is null 
     var dinnerFromTempData = TempData[ "Dinner" ] as Dinner; // Got my dinner object 

     return View("Action", new DinnerFormViewModel(dinnerFromTempData)); 
    } 
    } 

Voir Action:

<h2>Action</h2> 

<% using (Html.BeginForm()) {%> 

    <fieldset> 
     <legend>Fields</legend> 
     <p> 
      Name: <%= Html.TextBox("Name", Model.Dinner.Name) %> 
     </p> 
     <p> 
      <input type="submit" value="Save" /> 
     </p> 
    </fieldset> 

<% } %> 

uneAutreAction Vue:

<h2>AnotherAction</h2> 

<% using (Html.BeginForm()) {%> 

    <fieldset> 
     <legend>Fields</legend> 
     <p> 
      Name: 
      <%= Html.Encode(Model.Dinner.Name) %> 
     </p> 

     <p> 
      <input type="submit" value="Do Something" /> 
     </p> 
    </fieldset> 

<% } %> 
+0

Réinitialiser TempData sur AnotherAction n'aide pas. Ma compréhension est que TempData est seulement bon après RedirectToAction. Quoi qu'il en soit, j'ai aussi essayé cette méthode, avec et sans RedirectToAction. Bien sûr, RedirectToAction entre dans une boucle infinie appelant la version Get d'AnotherAction et la définition de TempData sans RedirectToAction ne me donne rien. Par conséquent, j'utilise le DinnerFormViewModel. Si vous regardez le code, lors de ma première action (Get), je fais la même chose.Ici, je peux modifier l'objet Dinner comme je le souhaite et je récupèrerai le même objet Dinner sur Action (Post). – Sai

+0

Jon, j'ai ajouté un exemple pour redéfinir TempData dans une autre action pour qu'il soit disponible pour la publication d'une autre action. Je suis capable de récupérer l'objet dîner de TempData avec succès. Cependant, étant donné que ma vue ne publie pas les variables de formulaire correctes dans AnotherAction, l'instance de dîner transmise à l'action est null. Pour info, je n'ai pas le projet de dîner nerd alors j'ai créé ma propre classe Dinner avec une seule propriété Name. –

+0

Ce flipper fonctionne Aaron, incroyable! Vous savez, je pensais que j'avais déjà essayé, alors j'ai suivi vos pas avec mon projet actuel et ça n'a pas marché. Puis j'ai commencé un nouveau projet avec juste votre code et ça a marché là-bas, donc je savais que j'avais quelques erreurs mineures quelque part. Alors je me suis avéré être un idiot. Je vous remercie! – Sai

0

Vous devriez obtenir le dîner du dépôt. Votre action doit ressembler à:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult AnotherAction(int dinnerId, FormCollection collection) 
{ 
    var dinner = dinnerRepository.Get(dinnerId); 
    ... do something with dinner ... 
    dinnerRepository.Save(dinner); 
    return RedirectToAction("AnotherAction", ... pass dinner id ...); 
} 

Les actions GET peuvent également être extraites du référentiel, vous ne pouvez donc passer que l'identifiant.

EDIT

Si vous voulez créer la page de style assistant, vous pouvez stocker les données saisies précédemment dans l'objet de session.

Session['CurrentDinner'] = dinner; 

Les données stockées dans la session sont conservées via des requêtes.

+0

Je ne passe pas le id autour, je passe l'objet entier. Et l'objet n'a pas encore été sauvegardé dans la base de données, donc je ne peux pas faire une "recherche" par magie depuis le dépôt. – Sai

+0

Ensuite, vous devriez lire sur les classeurs de modèle. Vous devez construire l'objet Dinner à partir des valeurs de formulaire. Pourquoi voulez-vous passer le dîner plusieurs fois sans le stocker dans la base de données? – LukLed

+0

Je vais lire sur les classeurs de modèle. Merci pour la suggestion. Je veux recueillir des informations de l'utilisateur à partir de deux vues différentes et quand j'ai l'information dont j'ai besoin, je vais le sauvegarder. Au lieu de faire des appels de base de données multiples inutiles. Ce qui me dérange, c'est que cela fonctionne pour une instance et ne fonctionne pas pour l'autre. C'est le même concept flippant. – Sai

2

Pour obtenir le format que vous attendez, vous devrez peut-être remplir certains champs masqués lorsque vous collecterez les informations à partir de différentes vues.

En outre, en utilisant le modèle de liaison, vous pouvez rendre votre code à peu mieux et éviter TempData dans les lieux:

public ActionResult Action() 
{ 
    Dinner dinner = new Dinner(); 
    return View(new DinnerFormViewModel(dinner)); 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Action(Dinner dinner) 
{ 
    try 
    { 
     return RedirectToAction("AnotherAction", dinner); 
    } 
    catch 
    { 
     return View(); 
    } 
} 

public ActionResult AnotherAction(Dinner dinner) 
{ 
    return View(new DinnerFormViewModel(dinner)); 

    //In this view is where you may want to populate some hidden fields with the Dinner properties that have already been entered... so when the Post action picks up the dinner object it will be fully populated 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult AnotherAction(Dinner dinner) 
{ 
    //work with fully populated Dinner object 
} 

Ainsi, dans la uneAutreAction vue que vous auriez quelque chose comme:

<% using(Html.BeginForm()) { %> 

    <%= Html.Hidden("dinnerProperty1") %> 
    <%= Html.Hidden("dinnerProperty2") %> 
    <%= Html.Hidden("dinnerProperty3") %> 
    <%= Html.TextBox("dinnerProperty4") %> 
    <%= Html.TextBox("dinnerProperty5") %> 
    <%= Html.TextBox("dinnerProperty6") %> 

<% } %> 

Il n'est pas convivial dans l'exemple ci-dessus, mais vous obtenez le point.

+0

Merci pour votre suggestion. Malheureusement, les champs cachés ne sont pas une option. Il y a une valeur unique que je ne veux pas que l'utilisateur renifle dans le code source et voir. Je peux peut-être chiffrer cela, mais ce serait mon dernier recours. Je vous remercie! – Sai

1

Vous ne pouvez pas passer des objets C# bruts des vues aux contrôleurs. Dans ASP.NET MVC, lorsqu'une action prend un objet pour un paramètre, ASP.NET MVC examine toutes les données POST/GET et recherche les valeurs qui coïncident avec les noms de propriété sur l'objet paramètre.

public ActionResult SomeAction(Dinner myDinner) 
{ 
     // do stuff 
} 

objet myDinner sera renseigné UNIQUEMENT si vous postez à l'action avec des champs de formulaire qui correspondent aux propriétés de l'objet du dîner (emplacement, date, etc.) ou si vous deviez placer cette information dans une URL GET (Dinners/SomeAction? Location = chicago & date = 12/1/2009 etc.)

Si vous ne pouvez absolument pas utiliser les champs cachés (comme suggéré par DM), Sessions est probablement votre seule option.

+0

Je suis d'accord avec Baddie. TempData utilise l'état de session derrière le rideau pour vous. J'arrêterais d'utiliser TempData et je stockerais simplement l'objet dans l'état de session directement. Bien sûr, seulement si vous ne pouvez pas utiliser les champs cachés. –

Questions connexes