Mam wieloetapowy proces rejestracji , wspierany przez pojedynczy obiekt w warstwie domeny , który ma zdefiniowane reguły walidacji we właściwościach.
Jak sprawdzić poprawność obiektu domeny, gdy domena jest podzielona na wiele widoków, a po opublikowaniu muszę częściowo zapisać obiekt w pierwszym widoku?
Myślałem o użyciu sesji, ale nie jest to możliwe, ponieważ proces jest długi, a ilość danych jest duża, więc nie chcę używać sesji.
Myślałem o zapisaniu wszystkich danych w relacyjnej bazie danych w pamięci (z tym samym schematem co główna baza danych), a następnie opróżnieniu tych danych do głównej bazy danych, ale pojawiły się problemy, które powodują, że powinienem routować między usługami (żądanymi w widokach), które pracują z główna baza danych i baza danych w pamięci.
Szukam eleganckiego i czystego rozwiązania (a dokładniej najlepszej praktyki).
AKTUALIZACJA I WYJAŚNIENIE:
@Darin Dziękuję za przemyślaną odpowiedź, dokładnie to zrobiłem do tej pory. Ale nawiasem mówiąc mam żądanie, które ma wiele załączników, projektuję Step2View
np. Który użytkownik może załadować w nim dokumenty asynchronicznie, ale te załączniki powinny być zapisane w tabeli z referencyjnym odniesieniem do innej tabeli, która powinna być wcześniej zapisana w Step1View
.
Dlatego powinienem zapisać obiekt domeny w Step1
(częściowo), ale nie mogę, ponieważ obsługiwany obiekt Core Domain, który jest częściowo mapowany na ViewModel Step1, nie może zostać zapisany bez właściwości, które pochodzą z przekonwertowanych Step2ViewModel
.
źródło
Odpowiedzi:
Po pierwsze, nie powinieneś używać żadnych obiektów domeny w swoich widokach. Powinieneś używać modeli widoku. Każdy model widoku będzie zawierał tylko właściwości wymagane przez dany widok, a także atrybuty walidacji specyficzne dla tego danego widoku. Więc jeśli masz kreatora 3 kroków, oznacza to, że będziesz mieć 3 modele widoków, po jednym dla każdego kroku:
i tak dalej. Wszystkie te modele widoków mogą być obsługiwane przez główny model widoku kreatora:
wtedy możesz mieć akcje kontrolera renderujące każdy krok procesu kreatora i przekazujące element main
WizardViewModel
do widoku. Gdy jesteś na pierwszym kroku wewnątrz akcji kontrolera, możesz zainicjowaćStep1
właściwość. Następnie w widoku można wygenerować formularz umożliwiający użytkownikowi wypełnienie właściwości dotyczących kroku 1. Po przesłaniu formularza akcja kontrolera zastosuje reguły walidacji tylko dla kroku 1:Teraz w widoku kroku 2 możesz użyć pomocnika Html.Serialize z kontraktów terminowych MVC w celu serializacji kroku 1 do ukrytego pola w formularzu (rodzaj ViewState, jeśli chcesz):
i wewnątrz akcji POST kroku 2:
I tak dalej, aż dojdziesz do ostatniego kroku, w którym będziesz miał
WizardViewModel
wypełnione wszystkie dane. Następnie zmapujesz model widoku na model domeny i przekażesz go do warstwy usług w celu przetworzenia. Warstwa usług może sama wykonywać dowolne reguły walidacji i tak dalej ...Jest też inna alternatywa: użycie javascript i umieszczenie wszystkiego na tej samej stronie. Istnieje wiele wtyczek jquery , które zapewniają funkcjonalność kreatora ( Stepy jest fajny). Zasadniczo jest to kwestia wyświetlania i ukrywania elementów div na kliencie, w którym to przypadku nie musisz już martwić się o utrzymywanie się stanu między krokami.
Ale bez względu na to, jakie rozwiązanie wybierzesz, zawsze używaj modeli widoków i przeprowadzaj walidację na tych modelach widoków. Dopóki trzymasz atrybuty walidacji adnotacji danych w modelach domeny, będziesz mieć bardzo duże problemy, ponieważ modele domeny nie są przystosowane do widoków.
AKTUALIZACJA:
OK, z uwagi na liczne komentarze dochodzę do wniosku, że moja odpowiedź nie była jasna. I muszę się zgodzić. Spróbuję więc dalej rozwinąć mój przykład.
Moglibyśmy zdefiniować interfejs, który powinny implementować wszystkie modele widoków krokowych (to tylko interfejs znaczników):
następnie zdefiniowalibyśmy 3 kroki dla kreatora, gdzie każdy krok zawierałby oczywiście tylko te właściwości, których wymaga, jak również odpowiednie atrybuty walidacji:
następnie definiujemy główny model widoku kreatora, który składa się z listy kroków i aktualnego indeksu kroków:
Następnie przechodzimy do kontrolera:
Kilka uwag na temat tego kontrolera:
[Deserialize]
atrybutów z biblioteki Microsoft Futures, więc upewnij się, że zainstalowanoMvcContrib
pakiet NuGet. Z tego powodu modele widoków powinny być ozdobione[Serializable]
atrybutemIStepViewModel
interfejs, więc aby miało to sens, potrzebujemy niestandardowego spinacza modelu.Oto powiązany segregator modelu:
Ten segregator używa specjalnego ukrytego pola o nazwie StepType, które będzie zawierać konkretny typ każdego kroku i które wyślemy na każde żądanie.
Ten model segregatora zostanie zarejestrowany w
Application_Start
:Ostatnim brakującym elementem układanki są widoki. Oto główny
~/Views/Wizard/Index.cshtml
widok:I to wszystko, czego potrzebujesz, aby to działało. Oczywiście, jeśli chcesz, możesz spersonalizować wygląd i działanie niektórych lub wszystkich kroków kreatora, definiując niestandardowy szablon edytora. Na przykład zróbmy to dla kroku 2. Więc definiujemy
~/Views/Wizard/EditorTemplates/Step2ViewModel.cshtml
częściową:Oto jak wygląda struktura:
Oczywiście jest miejsce na ulepszenia. Akcja Index POST wygląda następująco: s..t. Jest w nim za dużo kodu. Dalsze uproszczenie polegałoby na przeniesieniu wszystkich elementów infrastruktury, takich jak indeks, zarządzanie bieżącym indeksem, kopiowanie bieżącego kroku do kreatora… do innego segregatora modelu. Więc w końcu otrzymujemy:
czyli bardziej jak powinny wyglądać akcje POST. Zostawiam tę poprawę na następny raz :-)
źródło
Aby uzupełnić odpowiedź Amita Baggi, poniżej znajdziesz to, co zrobiłem. Nawet jeśli jest mniej elegancki, wydaje mi się to prostsze niż odpowiedź Darina.
Kontroler :
Modele:
źródło
Sugerowałbym utrzymanie stanu Complete Process na kliencie za pomocą Jquery.
W ten sposób możesz łatwo zbudować obiekt domeny bezpośrednio z danych posta formularza, aw przypadku, gdy dane zawierają błędy, zwróć poprawny kod JSON przechowujący wszystkie komunikaty o błędach i wyświetl je w div.
Podziel kroki
źródło
Kreatorzy to tylko proste kroki w przetwarzaniu prostego modelu. Nie ma powodu, aby tworzyć wiele modeli dla kreatora. Wszystko, co musisz zrobić, to utworzyć pojedynczy model i przekazać go między akcjami w jednym kontrolerze.
Powyższy coed jest głupi prosty, więc zamień tam swoje pola. Następnie zaczynamy od prostej akcji, która uruchamia naszego kreatora.
Wywołuje to widok „WizardStep1.cshtml (jeśli używasz maszynki do golenia). Jeśli chcesz, możesz użyć kreatora tworzenia szablonów. Będziemy po prostu przekierowywać post do innej akcji.
Należy zauważyć, że będziemy to umieszczać w innej akcji; akcja WizardStep2
W tej akcji sprawdzamy, czy nasz model jest prawidłowy, a jeśli tak, wysyłamy go do naszego widoku WizardStep2.cshtml, w przeciwnym razie odsyłamy z powrotem do kroku pierwszego z błędami walidacji. W każdym kroku wysyłamy go do następnego kroku, zatwierdzamy ten krok i przechodzimy dalej. Niektórzy doświadczeni programiści mogą dobrze powiedzieć, że nie możemy przechodzić między krokami, takimi jak ten, jeśli używamy atrybutów [Wymagane] lub innych adnotacji danych między krokami. Miałbyś rację, więc usuń błędy w elementach, które nie zostały jeszcze sprawdzone. jak poniżej.
Na koniec zapiszemy model raz do magazynu danych. Zapobiega to również użytkownikowi, który uruchamia kreatora, ale go nie kończy, aby nie zapisać niekompletnych danych w bazie danych.
Mam nadzieję, że ta metoda implementacji kreatora jest dużo łatwiejsza w użyciu i utrzymaniu niż którakolwiek z wcześniej wymienionych metod.
Dziękuje za przeczytanie.
źródło
Chciałem podzielić się moim własnym sposobem radzenia sobie z tymi wymaganiami. W ogóle nie chciałem używać SessionState, ani nie chciałem obsługiwać go po stronie klienta, a metoda serializacji wymaga MVC Futures, którego nie chciałem uwzględniać w moim projekcie.
Zamiast tego zbudowałem pomocnika HTML, który będzie iterował przez wszystkie właściwości modelu i generował niestandardowy ukryty element dla każdego z nich. Jeśli jest to złożona właściwość, będzie na niej działać rekurencyjnie.
W Twoim formularzu zostaną one przesłane do kontrolera wraz z danymi nowego modelu na każdym kroku „kreatora”.
Napisałem to dla MVC 5.
Teraz we wszystkich krokach swojego „kreatora” możesz użyć tego samego modelu podstawowego i przekazać właściwości modelu „Step 1,2,3” do helpera @ Html.HiddenClassFor przy użyciu wyrażenia lambda.
Jeśli chcesz, możesz nawet mieć przycisk Wstecz na każdym kroku. Wystarczy mieć w formularzu przycisk Wstecz, który wyśle go do akcji StepNBack na kontrolerze przy użyciu atrybutu formaction. Nie uwzględniono w poniższym przykładzie, ale tylko pomysł dla Ciebie.
W każdym razie tutaj jest podstawowy przykład:
Oto Twój MODEL
Oto Twój KONTROLER
Oto Twoje WIDOKI
Krok 1
Krok 2
Krok 3
źródło
Dodawanie więcej informacji z odpowiedzi @ Darin.
A co, jeśli masz oddzielny styl projektowania dla każdego kroku i chcesz zachować każdy z nich w oddzielnym widoku częściowym, lub co, jeśli masz wiele właściwości dla każdego kroku?
Podczas korzystania
Html.EditorFor
mamy ograniczenia do korzystania z częściowego widoku.Utwórz 3 częściowe widoki w
Shared
folderze o nazwie:Step1ViewModel.cshtml , Step3ViewModel.cshtml , Step3ViewModel.cshtml
Dla zwięzłości zamieszczam tylko pierwszy widok częściowy, inne kroki są takie same jak odpowiedź Darina.
Step1ViewModel.cs
Step1ViewModel.cshtml
Index.cshtml
Jeśli istnieje lepsze rozwiązanie, prosimy o komentarz, aby inni wiedzieli.
źródło
Jedną z opcji jest utworzenie zestawu identycznych tabel, w których będą przechowywane dane zebrane w każdym kroku. Następnie w ostatnim kroku, jeśli wszystko pójdzie dobrze, możesz utworzyć rzeczywistą jednostkę, kopiując tymczasowe dane i przechowując je.
Innym jest tworzenie
Value Objects
dla każdego kroku i przechowywanie wCache
lubSession
. Jeśli wszystko pójdzie dobrze, możesz utworzyć z nich obiekt domeny i zapisać goźródło