Mvc walidacja kilku textbox-ów

0

Witajcie

mam trzy textbox-y: txt1, txt2 i txt3.
Chciałbym aby jeśli wypełnię txt1 to nie muszę wypełniać txt2 i txt3 lub jeśli wypełnię txt2 i txt3 to nie muszę wypełniać txt1, oczywiście jeśli wszystkie są puste to musi pojawić się komunikat.

Jak prawidłowo rozwiązać problem po stronie serwera: w kontrolerze czy w modelu?
Czy walidacja w kontrolerze jest prawidłowa? Mam tu na myśli poprawność kodu.

Odbiegając już od powyższego, jeśli mam powiedzmy kilkanaście pozycji w modelu czy może być zastosowana walidacja część w modelu a część w kontrolerze?

1

W kontrolerze powinienes jedynie sprawdzac czy model jest poprawny, nie powinienes przeprowadzac walidacji w kontrolerze. Ja bym wydzielil osobna klase do walidowania modelu np. z uzyciem biblioteki fluentvalidation, zeby nie wynajdowac kola od nowa. Do prostych walidacji natomiast wystarcza atrybuty na polach modelu.

1

Kontroler ma sprawdzać tylko właściwość ModelState.IsValid, i na tej podstawie wykonywać akcję. Za walidację powinien odpowiadać (view)model.

Jeśli standardowe atrybuty walidacyjne są dla Ciebie niewystarczające, możesz zaimplementować w swoim modelu interfejs IValidatableObject i w metodzie Validate umieścić dodatkową logikę walidacji.

0

Dzięki za pomoc,
biblioteka FluentValidation wydaje się ciekawa, jednak bardziej do gustu przypadła mi propozycja @somekind

0

A co w sytuacji jak dochodzi jeszcze konieczność wykorzystania bazy danych, np. mamy w tabeli w bazie na trzech kolumnach zdefiniowany indeks unikatowy, w związku z czym wartości z 3. inputów w formularzu na stronie nie mogły wystąpić już w bazie. Czy możemy w tej metodzie Validate inicjalizować połączenie z bazą danych i sprawdzać następnie czy te wartości już wystapiły?

0

W malych aplikacjach - oczywiscie tak mozna zrobic.
W wiekszych posiadanie bezposredniego dostepu w warstwie webowej do warstwy, gdzie lezy kontekst bazy mogloby byc bardzo kosztowne, juz nie wspominajac o inicjalizowaniu w walidotarach view-modeli czegokolwiek z ta baza zwiazanego.

0

Czyli jak trzeba odwołać się do bazy danych to lepiej taką walidację umieścić w kontrolerze?

1

Nie, kontroler ma byc tak glupi jak to tylko mozliwe.

Jest kilka patternow aby to zrobic.

  1. Zlecamy akcje do serwisu, on sobie rzuca wyjatkiem jak cos jest nie tak, lapiemy w kontrolerze i wrzucamy do AddModelError.
  2. Oznaczamy akcje jako taka, ktora moze sie nie powiesc przez stworzenie wrappera na rezultat, typu OptionalResult<T>, gdzie T jest typem rezultatem. Wrapper ten ma dodakowe pola informujace o tym czy sie powiodlo i jak sie nie powiodlo to wiadomosc bledu.
  3. Mozna zrobic to co w punkcie 2. tylko odwrocic kolejnosc, tj. Stworzyc jakis interfejs IActionPossible z metodami IsPossible i WhyNotPossible, ktory serwis bedzie zwracac jako wynik akcji typu IsRegisterPossible.
  4. Mozna uzyc tez atrybutu Remote, wywolac przez niego odpowiednia akcje z kontrolera, kontroler wola serwis, ...
0

O to pierwsze rozwiązanie z metodą serwisu i wyjątkiem wydaje się super, dzięki :)

1

Wyjątek powinien świadczyć o tym, że coś poszło bardzo nie tak, np. dane w bazie są niespójne, coś nam ubiło transakcję, padł serwer bazy danych, pies zjadł kabel sieciowy, itp. W omawianym przypadku, możemy się spodziwać, że użytkownicy będą próbowali zapisywać niepoprawne dane, więc używanie w takiej sytuacji wyjątków nie jest prawidłowe. W ogólności, używanie wyjątków do walidacji jest nieprawidłowe.

Rozwiązanie nr 2 z OperationResult<T> jest lepsze i zapewne wydajniejsze.

0

chcę jeszcze powrócić do walidacji, czy źle będzie (mam tu na myśli ładny kod) jeśli w przypadku 3 pustych textbox-ów użyję 3 yield return, tzn. każdy komunikat dla każdego textbox-a

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (string.IsNullOrEmpty(txt1) && string.IsNullOrEmpty(txt2) && string.IsNullOrEmpty(txt3))
            {
                yield return new ValidationResult("Please enter txt1", new string[] { "txt1" });    
                yield return new ..... itd.
                yield return new ..... itd.       
            }      
        }

Działać działa ... tylko ... ?

1

nie widzę potrzeby, by wytaczać ciężkie działo w postaci yielda.

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (string.IsNullOrEmpty(txt1) && string.IsNullOrEmpty(txt2) && string.IsNullOrEmpty(txt3))
            {
                return new ValidationResult[]
                {
                    new ValidationResult(bla bla bla),
                    new ValidationResult(bla bla bla),
                    new ValidationResult(bla bla bla)
                };
            }
        }
0

Czemu tworzysz 3 obiekty ValidationResult, skoro sprawdzasz tylko 1 regule?

0

@Azarien coś z Twoim kodem nie tak, wywala komunikat "not all code paths return a value".
@n0name_l a masz jakiś pomysł? Próbuję przerobić kod Azariena aby zadziałał, ale cały czas wywala mi błędy.

coś wymyśliłem nie wiem czy to będzie dobre, ale też działa

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            List<ValidationResult> valRes = new List<ValidationResult>();

            if (string.IsNullOrEmpty(txt1) && string.IsNullOrEmpty(txt2) && string.IsNullOrEmpty(txt3))
            {                
                valRes.Add(new ValidationResult("AA", new string [] { "txt1" }));
                valRes.Add(new ValidationResult("BB", new string [] { "txt2" }));
                valRes.Add(new ValidationResult("CC", new string[] { "txt3" }));              
            }

            if (string.IsNullOrEmpty(txt1) && string.IsNullOrEmpty(txt2))
            {
                valRes.Add(new ValidationResult("BB", new string[] { "txt2" }));         
            }
            
            return valRes;
        }
1

coś z Twoim kodem nie tak, wywala komunikat "not all code paths return a value".

No to nie widzisz co jest nie tak?...

Dodaj else return null albo jeszcze lepiej else return new ValidationResult[0] żeby zwrócić nulla albo pustą tablicę w przeciwnym przypadku.

0

wybacz @Azarien zmęczenie

1 użytkowników online, w tym zalogowanych: 0, gości: 1