J'ai les deux méthodes d'action suivantes (simplifiées pour la question):
[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"]});
}
}
Donc, si la validation réussit, je redirige vers une autre page (confirmation).
Si une erreur se produit, je dois afficher la même page avec l'erreur.
Si je le fais return View()
, l'erreur est affichée, mais si je le fais return RedirectToAction
(comme ci-dessus), il perd les erreurs de modèle.
Je ne suis pas surpris par le problème, je me demande simplement comment vous gérez cela?
Je pourrais bien sûr simplement retourner la même vue au lieu de la redirection, mais j'ai une logique dans la méthode "Create" qui remplit les données de vue, que je devrais dupliquer.
Aucune suggestion?
Create
méthode qui remplit ViewData et appelez-la dans laCreate
méthode GET et également dans la branche de validation échouée dans laCreate
méthode POST.Create
avis, je l'ai simplement mis dans une méthodepopulateStuff
que j'appelle à la fois leGET
et le failPOST
.Réponses:
Vous devez avoir la même instance de
Review
sur votreHttpGet
action. Pour ce faire, vous devez enregistrer un objetReview review
dans la variable temporaire sur votreHttpPost
action, puis le restaurer surHttpGet
action.Si vous souhaitez que cela fonctionne même si le navigateur est actualisé après la première exécution de l'
HttpGet
action, vous pouvez le faire:Sinon, sur le bouton d'actualisation, l'objet
review
sera vide car il n'y aurait aucune donnée dansTempData["Review"]
.la source
TempData["ModelState"] = ModelState;
et que vous le restaurez avecModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
, cela fonctionneraitreturn Create(uniqueUri)
quand la validation échoue sur le POST? Comme les valeurs ModelState sont prioritaires sur le ViewModel transmis à la vue, les données publiées doivent toujours rester.J'ai dû résoudre ce problème moi-même aujourd'hui et je suis tombé sur cette question.
Certaines des réponses sont utiles (en utilisant TempData), mais ne répondent pas vraiment à la question posée.
Le meilleur conseil que j'ai trouvé était sur ce billet de blog:
http://www.jefclaes.be/2012/06/persisting-model-state-when-using-prg.html
En gros, utilisez TempData pour enregistrer et restaurer l'objet ModelState. Cependant, c'est beaucoup plus propre si vous résumez cela en attributs.
Par exemple
Ensuite, selon votre exemple, vous pouvez enregistrer / restaurer le ModelState comme ceci:
Si vous souhaitez également transmettre le modèle dans TempData (comme le suggère bigb), vous pouvez toujours le faire.
la source
Pourquoi ne pas créer une fonction privée avec la logique de la méthode "Create" et appeler cette méthode à la fois à partir de la méthode Get et Post et simplement renvoyer View ().
la source
return Create(new { uniqueUri = ... });
votre logique reste DRY (un peu comme appelerRedirectToAction
), mais sans les problèmes liés à la redirection, tels que perdre votre ModelState.je pourrais utiliser
TempData["Errors"]
Les TempData sont transmises à travers les actions préservant les données 1 fois.
la source
Je vous propose de retourner la vue, et d'éviter la duplication via un attribut sur l'action. Voici un exemple de remplissage pour afficher des données. Vous pouvez faire quelque chose de similaire avec votre logique de méthode de création.
Voici un exemple:
la source
J'ai une méthode qui ajoute l'état du modèle aux données temporaires. J'ai ensuite une méthode dans mon contrôleur de base qui vérifie les données temporaires pour toute erreur. S'il les a, il les rajoute à ModelState.
la source
Mon scénario est un peu plus compliqué car j'utilise le modèle PRG donc mon ViewModel ("SummaryVM") est dans TempData, et mon écran Summary l'affiche. Il y a un petit formulaire sur cette page pour POSTER des informations sur une autre action. La complication vient de l'obligation pour l'utilisateur de modifier certains champs dans SummaryVM sur cette page.
Summary.cshtml a le résumé de validation qui détectera les erreurs ModelState que nous allons créer.
Mon formulaire doit maintenant POSTER sur une action HttpPost pour Summary (). J'ai un autre très petit ViewModel pour représenter les champs modifiés, et le modelbinding me les fournira.
Le nouveau formulaire:
et l'action ...
Ici, je fais une validation et je détecte une mauvaise entrée, je dois donc retourner à la page Résumé avec les erreurs. Pour cela, j'utilise TempData, qui survivra à une redirection. S'il n'y a pas de problème avec les données, je remplace l'objet SummaryVM par une copie (mais avec les champs modifiés bien sûr modifiés) puis fais un RedirectToAction ("NextAction");
L'action de contrôleur Résumé, là où tout cela commence, recherche les erreurs dans les données temp et les ajoute à l'état du modèle.
la source
Microsoft a supprimé la possibilité de stocker des types de données complexes dans TempData, par conséquent, les réponses précédentes ne fonctionnent plus; vous ne pouvez stocker que des types simples comme des chaînes. J'ai modifié la réponse de @ asgeo1 pour qu'elle fonctionne comme prévu.
À partir de là, vous pouvez simplement ajouter l'annotation de données requise sur une méthode de contrôleur si nécessaire.
la source
Je préfère ajouter une méthode à mon ViewModel qui remplit les valeurs par défaut:
Ensuite, je l'appelle chaque fois que j'ai besoin des données originales comme celle-ci:
la source
Je donne juste un exemple de code ici Dans votre viewModel, vous pouvez ajouter une propriété de type "ModelStateDictionary" comme
et dans votre méthode d'action POST, vous pouvez écrire du code directement comme
puis attribuez ce modèle à Tempdata comme ci-dessous
et lorsque vous redirigez vers la méthode d'action d'un autre contrôleur, vous devez lire la valeur Tempdata dans le contrôleur
C'est tout. Vous n'êtes pas obligé d'écrire des filtres d'action pour cela. C'est aussi simple que le code ci-dessus si vous souhaitez obtenir des erreurs d'état du modèle vers une autre vue d'un autre contrôleur.
la source