Pergunta

Eu sou novo para ASP.NET MVC. Depois de trabalhar com o modelo ASP.NET tradicional por tanto tempo, ele está tomando algum tempo para eu começar a entender este modelo.

Estou passando por NerdDinner para entender como as coisas funcionam.

Então, eu tenho um objeto que precisa ser passada através de dois pontos de vista. Semelhante ao artigo NerdDinner Passo 6:. ViewData e ViewModel

Eu reter os dados de chegar a Post para a primeira vez, então eu colocá-lo em TempData e passá-lo para outra ação (anotherAction). Assim que eu receber meus dados em Get eu não posso mantê-lo no cargo.

Aqui está o meu 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
    }
}
Foi útil?

Solução

De acordo com esta post TempData é apenas cerca de 1 pedido único após seu conjunto.

Aqui está uma citação do post:

Se você definir TempData e sua ação, em seguida, retorna um ViewResult, em seguida, o próximo pedido, qualquer que seja ele passa a ser (uma solicitação AJAX, uma outra página que o usuário aberto em uma aba diferente, etc.), vai ver a TempData valor definido, e nenhum outro pedido vai vê-lo.

Assim, dado o código que eu estou vendo, você pode obter o jantar de TempData no get de AnotherAction que é o primeiro pedido depois de defini-lo em Action. No entanto olhando para o código e não ver o código para vista para AnotherAction não está claro como você está passando os dados para o cargo de AnotherAction. A instância jantar não vai ser em TempData para essa solicitação porque é o segundo pedido depois de colocá-lo em TempData. E se você não tem as marcas de formulário adequados definidos na visão AntoherAction o quadro não terá os valores de forma adequada para instanciar um objeto jantar no post.

Assim, ou você vai ter que redefinir TempData com a instância do jantar que a primeira chamada AnotherAction e, em seguida, recuperar o jantar de TempData no post AnotherAction, ou você pode seguir o conselho de dm e usar campos ocultos em sua vista.

IMO, você deve usar DMs maneira de fazer isso e evitar o uso de TempData.

Editar Adicionado exemplo de zerando o TempData em anotherAction para obter acesso a ele no post.

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

Action View:

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

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

<% } %>

Outras dicas

Para obter o formato que você está esperando você pode ter que preencher alguns campos ocultos que você coletar as informações a partir de vários pontos de vista.

Além disso, usando a ligação você pode fazer seu olhar código em pouco melhor e evitar TempData em lugares modelo:

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
}

Assim, no anotherAction ver você teria algo como:

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

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

<% } %>

Não há nenhuma facilidade de utilização no exemplo acima, mas você começa o ponto.

Você não pode passar C # objetos brutos de Visualizações aos controladores.

Em ASP.NET MVC, quando uma ação leva um objeto para um parâmetro, ASP.NET MVC olha para todos / GET dados e procura por valores que coincidem o POST com nomes de propriedades no objeto de parâmetro.

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

objeto myDinner será preenchido SOMENTE se você postar para a ação com campos de formulário que correspondem às propriedades do objeto Jantar (local, data, etc.) ou se você fosse para colocar essa informação em um GET URL (Jantares / SomeAction? location = chicago & data = 12/1/2009 etc.)

Se você absolutamente não pode usar campos ocultos (como DM sugerido), então Sessions é provavelmente a sua única opção.

Você deve obter o jantar a partir do repositório. Você ação deve 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 ...);
}
ações

Obter também pode tomar a partir do repositório, para que possa passar apenas id.

Editar

Se você quiser criar uma página de estilo de wizard, você pode armazenar previamente os dados introduzidos no objeto Session.

Session['CurrentDinner'] = dinner;

Os dados armazenados na sessão persistem através de pedidos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top