Domanda

Sono nuovo di ASP.NET MVC. Dopo aver lavorato con il modello ASP.NET tradizionale per così tanto tempo, mi ci vuole del tempo per capire questo modello.

Sto attraversando NerdDinner per capire come funzionano le cose.

Quindi, ho un oggetto che deve essere passato attraverso un paio di visualizzazioni. Simile all'articolo NerdDinner Passaggio 6: ViewData e ViewModel .

Conservo i dati da Get to Post per la prima volta, quindi li inserisco in TempData e li passo a un'altra azione (AnotherAction). Una volta che ottengo i miei dati su Get, non posso conservarli su Post.

Ecco il mio codice:

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
    }
}
È stato utile?

Soluzione

Secondo questo post di blog TempData è disponibile solo per 1 singola richiesta dopo il suo set.

Ecco una citazione dal post:

  

Se imposti TempData e la tua azione restituisce un ViewResult, la richiesta successiva, qualunque essa sia (una richiesta AJAX, un'altra pagina che l'utente ha aperto in un'altra scheda, ecc.), vedrà i TempData valore impostato e nessuna altra richiesta lo vedrà.

Quindi, dato il codice che sto vedendo, puoi ottenere la cena da TempData all'arrivo da AnotherAction che è la prima richiesta dopo averlo impostato su Action . Tuttavia, guardando il codice e non vedendo il codice per la visualizzazione di AnotherAction non è chiaro come si stiano passando i dati al post per AnotherAction . L'istanza della cena non sarà in TempData per quella richiesta perché è la seconda richiesta dopo averla impostata in TempData. E se non hai i tag del modulo appropriati impostati nella vista AntoherAction , il framework non avrà i valori di modulo appropriati per creare un'istanza di un oggetto cena nel post.

Quindi dovrai ripristinare TempData con l'istanza dinner, la prima chiamata AnotherAction e quindi recuperare la cena da TempData nel post AnotherAction , oppure tu puoi seguire i consigli di dm e utilizzare i campi nascosti nella tua vista.

IMO, dovresti usare DMs per farlo ed evitare di usare TempData.

Modifica Aggiunto esempio di reimpostazione di TempData in AnotherAction per ottenere l'accesso ad esso nel post.

Modello:

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

Visualizzazione azione:

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

<% } %>

AnotherAction View:

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

<% } %>

Altri suggerimenti

Per ottenere il formato che ti aspetti, potresti dover popolare alcuni campi nascosti mentre raccogli le informazioni da varie viste.

Inoltre, usando l'associazione del modello è possibile migliorare l'aspetto del codice ed evitare TempData in alcuni punti:

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
}

Quindi nella vista AnotherAction avresti qualcosa del tipo:

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

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

<% } %>

Nell'esempio sopra non c'è facilità d'uso ma si ottiene il punto.

Non è possibile passare oggetti C # non elaborati da Views a Controller.

In ASP.NET MVC, quando un'azione accetta un oggetto per un parametro, ASP.NET MVC esamina tutti i dati POST / GET e cerca valori che coincidono con i nomi delle proprietà sull'oggetto parametro.

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

L'oggetto myDinner verrà popolato SOLO se pubblichi sull'azione con campi modulo che corrispondono alle proprietà dell'oggetto Dinner (posizione, data, ecc.) o se dovessi inserire tali informazioni in un URL GET (Cene / SomeAction? location = chicago & amp; date = 12/1/2009 ecc.)

Se non puoi assolutamente usare i campi nascosti (come suggeriva DM), allora Sessioni è probabilmente la tua unica opzione.

Dovresti cenare dal repository. La tua azione dovrebbe essere come:

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

Le azioni GET possono anche essere eseguite dal repository, quindi è possibile passare solo id.

MODIFICA

Se si desidera creare una pagina di stile della procedura guidata, è possibile memorizzare i dati immessi in precedenza nell'oggetto Session.

Session['CurrentDinner'] = dinner;

I dati memorizzati nella sessione persistono attraverso le richieste.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top