Transferencia de datos del controlador a la vista, de nuevo al controlador, de nuevo a la vista

StackOverflow https://stackoverflow.com/questions/1814049

Pregunta

Soy nuevo en ASP.NET MVC. Después de trabajar con el modelo ASP.NET tradicional durante tanto tiempo, me está tomando un tiempo entender este modelo.

Estoy revisando NerdDinner para entender cómo funcionan las cosas.

Entonces, tengo un objeto que necesita pasar por un par de vistas. Similar al artículo NerdDinner Paso 6: ViewData y ViewModel .

Retengo los datos de Get to Post por primera vez, luego los pongo en TempData y los paso a otra acción (AnotherAction). Una vez que obtengo mis datos en Get, no puedo retenerlos en Post.

Aquí está mi código:

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
    }
}
¿Fue útil?

Solución

De acuerdo con esta publicación de blog TempData solo está disponible para 1 solicitud única después de su configuración.

Aquí hay una cita de la publicación:

  

Si configura TempData y su acción devuelve un ViewResult, entonces la siguiente solicitud, sea lo que sea (una solicitud AJAX, otra página que el usuario abrió en una pestaña diferente, etc.), verá TempData valor que establezca, y ninguna otra solicitud lo verá.

Entonces, dado el código que estoy viendo, puedes obtener la cena de TempData en el AnotherAction , que es la primera solicitud después de configurarlo en Action . Sin embargo, al mirar el código y no ver el código para ver AnotherAction , no está claro cómo está pasando los datos a la publicación de AnotherAction . La instancia de cena no va a estar en TempData para esa solicitud porque es la segunda solicitud después de configurarla en TempData. Y si no tiene las etiquetas de formulario adecuadas establecidas en la vista AntoherAction , el marco no tendrá los valores de formulario adecuados para instanciar un objeto de cena en la publicación.

Entonces, tendrá que restablecer TempData con la instancia de cena en la primera llamada AnotherAction y luego recuperar la cena de TempData en la publicación AnotherAction , o usted puede seguir los consejos de dm y usar campos ocultos en su vista.

En mi opinión, debe usar la forma de DM de hacer esto y evitar usar TempData.

Editar ejemplo agregado de restablecer TempData en AnotherAction para obtener acceso a él en la publicación.

Modelo:

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

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

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

Controlador:

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

Vista de acción:

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

<% } %>

Otra vista de acción:

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

<% } %>

Otros consejos

Para obtener el formato que espera, es posible que deba completar algunos campos ocultos a medida que recopila la información de varias vistas.

Además, utilizando el enlace de modelo, podría hacer que su código se vea un poco mejor y evitar TempData en algunos lugares:

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
}

Entonces, en la vista AnotherAction, tendría algo como:

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

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

<% } %>

No hay facilidad de uso en el ejemplo anterior, pero se entiende el punto.

No puede pasar objetos C # sin procesar de Vistas a Controladores.

En ASP.NET MVC, cuando una acción toma un objeto para un parámetro, ASP.NET MVC examina todos los datos POST / GET y busca valores que coincidan con los nombres de propiedades en el objeto de parámetro.

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

El objeto myDinner se rellenará SOLO si publica en la acción con campos de formulario que corresponden a las propiedades del objeto Cena (ubicación, fecha, etc.) o si coloca esa información en una URL GET (Dinners / SomeAction? location = chicago & amp; date = 12/1/2009 etc.)

Si absolutamente no puede usar campos ocultos (como sugirió DM), Sessions es probablemente su única opción.

Deberías obtener la cena del repositorio. Tu acción debería ser como:

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

Las acciones GET también pueden tomarse del repositorio, por lo que solo puede pasar la identificación.

EDITAR

Si desea crear una página de estilo de asistente, puede almacenar datos ingresados ??previamente en el objeto Sesión.

Session['CurrentDinner'] = dinner;

Los datos almacenados en la sesión persisten a través de solicitudes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top