Question

Je suis nouveau sur ASP.NET MVC. Après avoir travaillé avec le modèle ASP.NET traditionnel pendant si longtemps, il me faut un peu de temps pour comprendre ce modèle.

Je passe par NerdDinner pour comprendre comment les choses fonctionnent.

J'ai donc un objet qui doit être transmis à travers plusieurs vues. Semblable à l'article NerdDinner Étape 6: ViewData et ViewModel .

Je conserve les données de Get to Post pour la première fois, puis je les mets dans TempData et les passe à une autre action (AnotherAction). Une fois mes données obtenues 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
    }
}
Était-ce utile?

La solution

Selon ce article de blog , TempData est uniquement disponible pour 1 seule requête après son envoi.

Voici une citation de l'article:

  

Si vous définissez TempData et que votre action retourne alors un ViewResult, la requête suivante, quelle qu'elle soit (une requête AJAX, une autre page ouverte par l'utilisateur dans un onglet différent, etc.), s'affichera dans TempData. valeur que vous définissez et aucune autre requête ne la verra.

Donc, étant donné le code que je vois, vous pouvez obtenir le dîner de TempData à partir de AnotherAction , qui est la première demande après son paramétrage sur Action . . Toutefois, si vous examinez le code et ne le voyez pas pour la vue de AnotherAction , vous ne savez pas comment vous transmettez les données à la publication de AnotherAction . L'instance de dîner ne sera pas dans TempData pour cette demande car c'est la deuxième demande après que vous l'ayez définie dans TempData. Et si les balises de formulaire appropriées ne sont pas définies dans la vue AntoherAction , la structure n'aura pas les valeurs de formulaire appropriées pour instancier un objet dîner dans la publication.

Donc vous devez soit réinitialiser TempData avec l’instance de dîner le premier appel AnotherAction , puis récupérer le dîner hors de TempData dans la publication AnotherAction , ou vous pouvez suivre les conseils de dm et utiliser des champs cachés dans votre vue.

IMO, vous devez utiliser cette méthode et éviter d'utiliser TempData.

Modifier Ajout d'un exemple de réinitialisation de TempData dans AnotherAction pour y accéder ultérieurement.

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

Contrôleur:

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

Vue d’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>

<% } %>

Vue AnotherAction:

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

<% } %>

Autres conseils

Pour obtenir le format attendu, vous devrez peut-être renseigner certains champs masqués à mesure que vous collectez les informations à partir de différentes vues.

De plus, en utilisant la liaison de modèle, vous pouvez améliorer l'apparence de votre code et éviter TempData par endroits:

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 vue AnotherAction, vous obtiendrez quelque chose comme:

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

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

<% } %>

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

Vous ne pouvez pas transmettre d’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é de l'objet paramètre.

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

L'objet myDinner sera renseigné UNIQUEMENT si vous postez dans l'action avec des champs de formulaire correspondant aux propriétés de l'objet Dinner (emplacement, date, etc.) ou si vous deviez placer ces informations dans une URL GET (Dinners / SomeAction?). emplacement = chicago & date = 12/1/2009 etc.)

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

Vous devriez obtenir le dîner du référentiel. Votre action devrait 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, de sorte que vous ne pouvez transmettre que l'identifiant.

MODIFIER

Si vous souhaitez créer une page de style d’assistant, vous pouvez stocker les données saisies précédemment dans l’objet Session.

Session['CurrentDinner'] = dinner;

Les données stockées dans Session persistent lors des requêtes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top