Czy ktoś może mi podać zwięzłą definicję roli ModelState w Asp.net MVC (lub link do niej). W szczególności muszę wiedzieć, w jakich sytuacjach dzwonienie jest konieczne lub pożądane ModelState.Clear()
.
Trochę otwarte, huh ... przepraszam, myślę, że może pomóc, jeśli powiem ci, co naprawdę robię:
Mam akcję edycji na kontrolerze o nazwie „Strona”. Kiedy po raz pierwszy widzę formularz do zmiany szczegółów strony, wszystko ładuje się poprawnie (wiązanie z obiektem „MyCmsPage”). Następnie klikam przycisk, który generuje wartość dla jednego z pól obiektu MyCmsPage ( MyCmsPage.SeoTitle
). Generuje dobrze i aktualizuje obiekt, a następnie zwracam wynik akcji z nowo zmodyfikowanym obiektem strony i oczekuję, że odpowiednie pole tekstowe (renderowane przy użyciu <%= Html.TextBox("seoTitle", page.SeoTitle)%>
) zostanie zaktualizowane ... ale niestety wyświetla wartość ze starego modelu, który został załadowany.
Pracowałem nad tym, używając, ModelState.Clear()
ale muszę wiedzieć, dlaczego / jak to działa, więc nie robię tego na ślepo.
PageController:
[AcceptVerbs("POST")]
public ActionResult Edit(MyCmsPage page, string submitButton)
{
// add the seoTitle to the current page object
page.GenerateSeoTitle();
// why must I do this?
ModelState.Clear();
// return the modified page object
return View(page);
}
Aspx:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyCmsPage>" %>
....
<div class="c">
<label for="seoTitle">
Seo Title</label>
<%= Html.TextBox("seoTitle", page.SeoTitle)%>
<input type="submit" value="Generate Seo Title" name="submitButton" />
</div>
źródło
Odpowiedzi:
Myślę, że to błąd w MVC. Walczyłem z tym problemem godzinami dzisiaj.
Biorąc to pod uwagę:
Widok jest renderowany z oryginalnym modelem, ignorując zmiany. Pomyślałem więc, że może nie podoba mi się używanie tego samego modelu, więc spróbowałem tak:
I nadal widok renderuje się z oryginalnym modelem. Dziwne jest to, że kiedy umieszczam punkt przerwania w widoku i badam model, ma on zmienioną wartość. Ale strumień odpowiedzi ma stare wartości.
W końcu odkryłem tę samą pracę, którą zrobiłeś:
Działa zgodnie z oczekiwaniami.
Nie sądzę, żeby to była „funkcja”, prawda?
źródło
Aktualizacja:
View()
z akcji POST. Zamiast tego użyj PRG i przekieruj do GET, jeśli akcja zakończy się sukcesem.View()
z działania POST, zrób to dla walidacji formularza i zrobić to tak MVC został zaprojektowany przy użyciu wbudowanego w pomocników. Jeśli zrobisz to w ten sposób, nie powinieneś używać.Clear()
ModelState
ponieważ i tak nie powinieneś go używać.Stara odpowiedź:
ModelState w MVC służy przede wszystkim do opisywania stanu obiektu modelu w dużej mierze w odniesieniu do tego, czy ten obiekt jest prawidłowy, czy nie. Ten samouczek powinien wiele wyjaśnić.
Zasadniczo nie ma potrzeby czyszczenia ModelState, ponieważ jest on obsługiwany przez silnik MVC. Wyczyszczenie go ręcznie może spowodować niepożądane rezultaty podczas próby przestrzegania najlepszych praktyk walidacji MVC.
Wygląda na to, że próbujesz ustawić domyślną wartość tytułu. Należy to zrobić, gdy instancja obiektu modelu jest tworzona (warstwa domeny gdzieś lub w samym obiekcie - bez parametrów), przy akcji get tak, że przechodzi do strony za pierwszym razem lub całkowicie na kliencie (przez ajax lub coś w tym rodzaju) aby wyglądało to tak, jakby użytkownik je wprowadził i wraca z kolekcją opublikowanych formularzy. W pewnym sensie Twoje podejście do dodawania tej wartości podczas odbierania kolekcji formularzy (w akcji POST // Edycja) powoduje to dziwne zachowanie, które może sprawić, że
.Clear()
pozornie zadziała. Zaufaj mi - nie chcesz używać przezroczystego. Wypróbuj inny pomysł.źródło
Jeśli chcesz wyczyścić wartość dla pojedynczego pola, uważam, że przydatna jest następująca technika.
Uwaga: Zmień „Klucz” na nazwę pola, które chcesz zresetować.
źródło
Cóż, ModelState w zasadzie przechowuje bieżący stan modelu pod względem walidacji
ModelErrorCollection: Reprezentuj błędy, gdy model próbuje powiązać wartości. dawny.
lub jak parametr w ActionResult
ValueProviderResult : Przechowuj szczegóły dotyczące próby powiązania z modelem. dawny. AttemptedValue, Culture, RawValue .
Należy zachować ostrożność podczas używania metody Clear (), ponieważ może ona prowadzić do niespodziewanych wyników. I stracisz kilka fajnych właściwości ModelState, takich jak AttemptedValue, jest to używane przez MVC w tle do ponownego wypełnienia wartości formularza w przypadku błędu.
źródło
Miałem przypadek, w którym chciałem zaktualizować model sumowanego formularza i nie chciałem przekierowywać do działania ze względu na wydajność. Poprzednie wartości ukrytych pól były zachowywane w moim zaktualizowanym modelu - powodując różnego rodzaju problemy !.
Kilka wierszy kodu szybko zidentyfikowało elementy w ModelState, które chciałem usunąć (po walidacji), więc nowe wartości zostały użyte w postaci: -
źródło
Cóż, wydaje się, że wielu z nas zostało przez to ugryzionych i chociaż powód, dla którego tak się dzieje, ma sens, potrzebowałem sposobu, aby upewnić się, że wartość mojego Modelu została pokazana, a nie ModelState.
Niektórzy sugerowali
ModelState.Remove(string key)
, ale nie jest oczywiste, cokey
powinno być, szczególnie w przypadku modeli zagnieżdżonych. Oto kilka metod, które wymyśliłem, aby w tym pomóc.RemoveStateFor
Metoda zajmieModelStateDictionary
, model i wyrażenie dla żądanej własności i usuń go.HiddenForModel
można użyć w widoku, aby utworzyć ukryte pole wejściowe przy użyciu tylko wartości z modelu, najpierw usuwając jego wpis ModelState. (Można to łatwo rozszerzyć dla innych metod rozszerzenia pomocnika).Zadzwoń z kontrolera takiego jak ten:
lub z takiego widoku:
Używa
System.Web.Mvc.ExpressionHelper
do uzyskania nazwy właściwości ModelState.źródło
Chciałem zaktualizować lub zresetować wartość, jeśli nie została ona do końca zweryfikowana, i napotkałem ten problem.
Prosta odpowiedź, ModelState.Remove, jest ... problematyczna ... ponieważ jeśli używasz pomocników, tak naprawdę nie znasz nazwy (chyba że trzymasz się konwencji nazewnictwa). Chyba że utworzysz funkcję, której zarówno niestandardowy pomocnik, jak i kontroler będą mogły użyć do uzyskania nazwy.
Ta funkcja powinna zostać zaimplementowana jako opcja w pomocniku, gdzie domyślnie nie jest to możliwe , ale jeśli chcesz, aby nieakceptowane dane wejściowe zostały ponownie wyświetlone, możesz to po prostu powiedzieć.
Ale przynajmniej teraz rozumiem problem;).
źródło
Remove()
we właściwym kluczu.W końcu to rozumiem. Mój niestandardowy modelBinder, który nie był rejestrowany i robi to:
Więc coś, co robiło domyślne powiązanie modelu, musiało być przyczyną problemu. Nie wiem co, ale mój problem został przynajmniej rozwiązany teraz, gdy mój segregator modelu niestandardowego jest rejestrowany.
źródło
Generalnie, gdy walczysz ze standardowymi praktykami ram, nadszedł czas, aby ponownie rozważyć swoje podejście. W takim przypadku zachowanie ModelState. Na przykład, jeśli nie chcesz, aby stan modelu po POST, rozważ przekierowanie do get.
EDYTOWANO, aby odpowiedzieć na komentarz dotyczący kultury
Oto, czego używam do obsługi wielokulturowej aplikacji MVC. Najpierw podklasy obsługi trasy:
A oto jak łączę trasy. Po utworzeniu tras dodaję mojego subagenta (example.com/subagent1, example.com/subagent2 itd.), A następnie kod kultury. Jeśli potrzebujesz tylko kultury, po prostu usuń subagenta z programów obsługi tras i tras.
źródło
Cóż, wydawało się, że to działa na mojej stronie Razor i nigdy nawet nie przeszedłem w obie strony do pliku .cs. To jest stary sposób HTML. Może się przydać.
źródło