Tenho os dois métodos de ação a seguir (simplificado para a pergunta):
[HttpGet]
public ActionResult Create(string uniqueUri)
{
// get some stuff based on uniqueuri, set in ViewData.
return View();
}
[HttpPost]
public ActionResult Create(Review review)
{
// validate review
if (validatedOk)
{
return RedirectToAction("Details", new { postId = review.PostId});
}
else
{
ModelState.AddModelError("ReviewErrors", "some error occured");
return RedirectToAction("Create", new { uniqueUri = Request.RequestContext.RouteData.Values["uniqueUri"]});
}
}
Então, se a validação passar, redireciono para outra página (confirmação).
Se ocorrer um erro, preciso exibir a mesma página com o erro.
Se o fizer return View()
, o erro será exibido, mas se o fizer return RedirectToAction
(como acima), ele perderá os erros de modelo.
Não estou surpreso com o problema, apenas me perguntando como vocês lidam com isso?
Eu poderia, é claro, apenas retornar a mesma visualização em vez do redirecionamento, mas tenho lógica no método "Criar" que preenche os dados da visualização, que eu teria que duplicar.
Alguma sugestão?
Create
método que preenche ViewData e chame-o noCreate
método GET e também no branch de validação com falha noCreate
método POST.Create
opinião, eu apenas coloquei em algum métodopopulateStuff
que chamo emGET
e na falhaPOST
.Respostas:
Você precisa ter a mesma instância de
Review
em suaHttpGet
ação. Para fazer isso, você deve salvar um objetoReview review
na variável temporária em suaHttpPost
ação e restaurá-lo naHttpGet
ação.Se quiser que isso funcione mesmo que o navegador seja atualizado após a primeira execução da
HttpGet
ação, você pode fazer o seguinte:Caso contrário, em objeto de botão de atualização
review
estará vazio porque não haveria quaisquer dados noTempData["Review"]
.fonte
TempData["ModelState"] = ModelState;
e restauráModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
-lo, ele funcionaráreturn Create(uniqueUri)
quando a validação falha no POST? Como os valores de ModelState têm precedência sobre o ViewModel passado para a visualização, os dados postados ainda devem permanecer.Eu tive que resolver esse problema sozinho hoje, e me deparei com essa pergunta.
Algumas das respostas são úteis (usando TempData), mas não respondem realmente à pergunta em questão.
O melhor conselho que encontrei foi nesta postagem do blog:
http://www.jefclaes.be/2012/06/persisting-model-state-when-using-prg.html
Basicamente, use TempData para salvar e restaurar o objeto ModelState. No entanto, é muito mais limpo se você abstrair isso em atributos.
Por exemplo
Então, de acordo com seu exemplo, você pode salvar / restaurar o ModelState assim:
Se você também quiser passar o modelo em TempData (como bigb sugerido), você ainda pode fazer isso também.
fonte
Por que não criar uma função privada com a lógica no método "Create" e chamar esse método de ambos os métodos Get e Post e apenas retornar View ().
fonte
return Create(new { uniqueUri = ... });
sua lógica permanece DRY (muito parecido com a chamadaRedirectToAction
), mas sem os problemas transportados pelo redirecionamento, como perdendo seu ModelState.eu poderia usar
TempData["Errors"]
TempData são passados através de ações preservando dados 1 vez.
fonte
Eu sugiro que você retorne a visualização e evite a duplicação por meio de um atributo na ação. Aqui está um exemplo de preenchimento para visualizar dados. Você poderia fazer algo semelhante com a lógica do método de criação.
Aqui está um exemplo:
fonte
Eu tenho um método que adiciona o estado do modelo aos dados temporários. Então, tenho um método em meu controlador de base que verifica se há erros nos dados temporários. Se tiver, ele os adiciona de volta ao ModelState.
fonte
Meu cenário é um pouco mais complicado porque estou usando o padrão PRG, então meu ViewModel ("SummaryVM") está em TempData e minha tela de resumo o exibe. Há um pequeno formulário nesta página para POSTAR algumas informações para outra ação. A complicação veio da necessidade de o usuário editar alguns campos no SummaryVM nesta página.
Summary.cshtml tem o resumo de validação que detectará erros de ModelState que criaremos.
Meu formulário agora precisa ser POST em uma ação HttpPost para Summary (). Eu tenho outro ViewModel muito pequeno para representar os campos editados, e modelbinding vai trazer isso para mim.
O novo formulário:
e a ação ...
Aqui eu faço algumas validações e detecto algumas entradas incorretas, então preciso retornar à página Resumo com os erros. Para isso eu uso TempData, que sobreviverá a um redirecionamento. Se não houver problemas com os dados, substituo o objeto SummaryVM por uma cópia (mas com os campos editados alterados, é claro) e, em seguida, faço um RedirectToAction ("NextAction");
A ação do controlador de Resumo, onde tudo isso começa, procura por quaisquer erros no tempdata e os adiciona ao modelstate.
fonte
A Microsoft removeu a capacidade de armazenar tipos de dados complexos em TempData, portanto, as respostas anteriores não funcionam mais; você só pode armazenar tipos simples como strings. Alterei a resposta de @ asgeo1 para funcionar conforme o esperado.
A partir daqui, você pode simplesmente adicionar a anotação de dados necessária em um método do controlador conforme necessário.
fonte
Prefiro adicionar um método ao meu ViewModel que preencha os valores padrão:
Então eu chamo isso sempre que preciso dos dados originais, como este:
fonte
Estou dando apenas um exemplo de código aqui. Em seu viewModel, você pode adicionar uma propriedade do tipo "ModelStateDictionary" como
e em seu método de ação POST, você pode escrever código diretamente como
e então atribuir este modelo a Tempdata como abaixo
e quando você redireciona para o método de ação de outro controlador, então no controlador você tem que ler o valor Tempdata
É isso aí. Você não precisa escrever filtros de ação para isso. Isso é tão simples quanto o código acima se você deseja obter os erros de estado do modelo para outra visualização de outro controlador.
fonte