2011-07-01 11 views
5

Jedną z powszechnych zalecanych praktyk w asp.net mvc jest to, że powinieneś stworzyć viewmodels specyficzne dla każdego widoku.Gdzie umieszczasz swoją walidację w asp.net mvc 3?

Po wykonaniu tej czynności i wywołaniu metody ModelState.IsValid w kontrolerze skutecznie sprawdza się poprawność modelu widoku, ale nie obiektu biznesowego.

Jakie jest konwencjonalne podejście do radzenia sobie z tym?

public class Person 
{ 
public int ID {get; set;}; 

[Required] 
public string Name {get; set;} 

[Required] 
public string LastName {get; set;} 

public virtual ICollection<Exam> Exams {get; set;} 

} 

public class PersonFormViewModel 
{ 

public int ID {get; set;};  


[Required] 
public string Name {get; set;} 

[Required] 
public string LastName {get; set;} 

} 

To jest dokładnie to, co mam teraz, ale nie jestem pewien, czy [Wymagane] atrybut powinien pojawić się po obu modeli lub po prostu ViewModel lub tylko model działalności.

Wszelkie wskazówki na ten temat są mile widziane.

Więcej linków popierających moje twierdzenie, że dobrym zwyczajem jest zawsze używać modeli widoku.

How to add validation to my POCO(template) classes

http://blogs.msdn.com/b/simonince/archive/2010/01/26/view-models-in-asp-net-mvc.aspx

+0

Jaki jest dokładnie twój "model biznesowy"? –

+0

Osoba to klasa śledzona przez EntityFramework. PersonViewModel oczywiście nie jest .. przeczytaj wpis na blogu, z którym się łączyłem i zrozumiesz, jakie praktyki próbuję podążać ... stąd pytanie, gdzie powinna iść logika walidacji. – ignaciofuentes

+0

Dzięki - przepraszam, zeskanowałem artykuł i szukałem w nim "modelu biznesowego", ale bez trafień. –

Odpowiedz

7

Moje preferencje to zrobić walidacji wejścia na widoku modeli i walidacji biznesu na model domeny.

Innymi słowy, wszelkie adnotacje danych, takie jak wymagane pola, sprawdzanie długości, wyrażenie regularne itp., Powinny być wykonywane w modelach widoku i dodawane do stanu modelu po wystąpieniu błędu.

Prawdopodobnie będziesz mieć reguły biznesowe/domeny, które polegają na czymś więcej niż tylko "formularzu", więc powinieneś to zrobić w modelach domenowych (wykonaj walidację po ich odwzorowaniu) lub warstwa usługowa.

Wszystkie nasze modele mają metodę zwaną "Validate", którą nazywamy usługami przed utrwaleniem. Wyrzucają niestandardowe wyjątki, jeśli nie sprawdzą poprawności biznesowej, która zostanie przechwycona przez kontroler i dodana do stanu modelu.

Może nie być filiżanką herbaty dla wszystkich, ale jest spójna.

Przykład walidacji gospodarczej, zgodnie z wnioskiem:

Oto przykład z modelu domeny mamy, która reprezentuje ogólny "post" (pytanie, zdjęć, wideo, itp):

public abstract class Post 
{ 
    // .. fields, properties, domain logic, etc 

    public void Validate() 
    { 
     if (!this.GeospatialIdentity.IsValidForThisTypeOfPost()) 
     throw new DomainException(this, BusinessException.PostNotValidForThisSpatial.); 
    } 
} 

Widzisz tam, sprawdzam reguły biznesowe i rzucam niestandardowe wyjątki. DomainException to nasza baza i mamy wiele pochodnych implementacji. Mamy wyliczenie o nazwie BusinessException, które zawiera wartości wszystkich naszych wyjątków. W wyliczeniach używamy metod rozszerzeń, aby zapewnić komunikat o błędzie oparty na zasobach.

To nie jest po prostu pole na sprawdzanie modelu, np. "Wszystkie posty muszą mieć temat", ponieważ chociaż jest to część domeny, to przede wszystkim walidacja danych wejściowych i tym samym jest obsługiwana za pomocą adnotacji danych w modelu widoku.

Teraz kontroler:

[HttpPost] 
public ActionResult Create(QuestionViewModel viewModel) 
{ 
    if (!ModelState.IsValid) 
    return View(viewModel); 

    try 
    { 
     // Map to ViewModel 
     var model = Mapper.Map<QuestionViewModel,Question>(viewModel); 

     // Save. 
     postService.Save(model); // generic Save method, constraint: "where TPost: Post, new()". 

     // Commit. 
     unitOfWork.Commit(); 

     // P-R-G 
     return RedirectToAction("Index", new { id = model.PostId }); 
    } 
    catch (Exception exc) 
    { 
     var typedExc = exc as DomainException; 

     if (typedExc != null) 
     { 
     // Internationalised, user-friendly domain exception, so we can show 
     ModelState.AddModelError("Error", typedExc.BusinessError.ToDescription()); 
     } 
     else 
     { 
     // Could be anything, e.g database exception - so show generic msg. 
     ModelState.AddModelError("Error", "Sorry, an error occured saving the Post. Support has been notified. Please try again later."); 
     } 
    } 

    return View(viewModel); 
} 

Tak, przez czas my trafiamy do „Zapisz” metody na służbie, model przeszedł sprawdzania poprawności danych wejściowych. Następnie metoda Save wywołuje post.Validate(), wywołując reguły biznesowe.

Jeśli zostanie zgłoszony wyjątek, kontroler go złapie i wyświetli komunikat. Jeśli przejdzie, zostanie użyta metoda Save i wystąpi kolejny błąd (na przykład 90% czasu, to Entity Framework), pokazujemy ogólny komunikat o błędzie.

Tak jak powiedziałem, nie dla wszystkich, ale to działa dobrze dla naszego zespołu. Mamy wyraźne oddzielenie prezentacji i walidacji domen oraz spójny przepływ kontroli od surowego HTTP POST do przekierowania po pomyślnym zakończeniu.

HTH

+0

mogłabyś zamieścić mały przykład tego? szczególnie metoda kontrolera. – ignaciofuentes

+2

@NachoF - jak chcesz, przykład został dodany. – RPM1984

0

Zazwyczaj Twój ViewModel będą zawierać odniesienie do swojej model - ViewModel jest konieczne tylko wtedy, gdy trzeba wyświetlić dodatkowe informacje w widoku, który nie jest dostępny w modelu istnieje nie ma potrzeby replikowania danych już istniejących.

+0

Więc mówisz, że przekazujesz obiekty modelu biznesowego do widoku, gdy nie potrzebujesz dodatkowych informacji, które nie są zawarte w samym obiekcie biznesowym? – ignaciofuentes

+0

Poprawnie, na przykład tutaj http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx Scott Guthrie przekazuje swój typ Person zawierający adnotacje danych do jego widok w kontrolerze. – devdigital

+0

Właśnie przeczytałem artykuł, który połączyłeś i nie widzisz nigdzie, gdzie Jimmy mówi "nie powinieneś wysyłać swoich modeli biznesowych do swoich poglądów". W rzeczywistości słowo "nie" nie pojawia się w żadnym miejscu w artykule, a Jimmy stwierdza: "Oczywiście, wiele z tych opinii jest naprawdę ważnych tylko w ograniczeniach naszego projektu" i "te opinie mogą lub nie mogą odnosić się do projektu, który pracować nad. Znowu, wzorce dotyczą kompromisów, korzyści i zobowiązań. " – devdigital

4

Klasa "kumpel" MetaData jest dokładnie tym, do czego służy. Walidacja jest tworzony raz, ale może być stosowany zarówno na modelu i ViewModel klasach:

public class PersonMetaData 
{ 
    [Required] 
    public string Name {get; set;} 

    [Required] 
    public string LastName {get; set;} 
} 

[MetadataType(typeof(PersonMetaData))] 
public class Person 
{ 
    public string Name {get; set;} 
    public string LastName {get; set;} 
} 

[MetadataType(typeof(PersonMetaData))] 
public class PersonFormViewModel 
{ 
    public string Name {get; set;} 
    public string LastName {get; set;} 
} 
+0

Sprawdź, jakie są konsekwencje perforacji w przejściu całej klasy biznesowej do widoku i użycia jako ViewModel do edycji edytowalnych danych i ponownego przesłania ich do kontrolera i przekazania go do ORM x 1000 wyświetleń na minutę VS przy użyciu ViewModel specyficznego dla widoku i przekazanie tego modelu do firmy, aby przekształcić go w prawidłowe dane. Dane zawsze będą zajęte, ale w jaki sposób klasy znajomych wpływają na obciążenie serwerów w ViewEngine? Pewnie, że jest to łatwe, ale rzucanie serwerem jest łatwe, ponieważ nie zdajemy sobie sprawy z konsekwencji tych działań. – ppumkin

1

zważywszy, że zawsze przechodzą ViewModels do widoku i twoi model domeny nie są narażone na użytkownika końcowego przez poglądów Potem don nie widzą potrzeby sprawdzania samego modelu domeny. Na przykład, jeśli otrzymasz PersonViewModel z widoku za pośrednictwem postu formularza, przekształcisz go w Person Model (być może za pośrednictwem automapper itp.) Tylko wtedy, gdy PersonViewModel jest ważny. Uważam więc, że walidacje wejściowe powinny pozostać z modelami widoku, ponieważ są one tym, które są zobowiązane do wprowadzenia.

2

Świetna odpowiedź przez RPM1984 i miły przykładowy kod.

Mój pogląd jest taki, że używanie wariantu 2 od samego początku jest pragmatyczne w równowadze pomiędzy produktywnością a strukturą, ale w niektórych przypadkach trzeba być gotowym na przejście do wariantu 3, więc opowiadam się za mieszanką tych dwóch podejść, logiczny. Wzory & Praktyki jednak zalecają zawsze robienie Wariantu 3, ponieważ jest to idealne rozdzielenie problemów itp. I unika się stosowania dwóch podejść w tym samym rozwiązaniu, których niektórzy nie lubią, a wielu klientów, z którymi pracuję, wybiera wariant Variant 3 i biegnie z tym dla wszystkich modeli.

Myślę, że kluczem jest to, co powiedział RPM1984 - ponowne wykorzystanie podmiotów biznesowych w modelach widoków jest użyteczne w celu ponownego użycia sprawdzania poprawności, ale należy pamiętać, że często logika biznesowa musi również wymagać innej walidacji (np. Sprawdzanie rekord już nie istnieje). Jeśli użyjesz Wariantu 3, umocnisz swoją weryfikację Modelu Podglądu wyłącznie na potrzeby swoich poglądów (kosztem niewielkiego dodatkowego wysiłku), ale zawsze będziesz potrzebował również jakiejś walidacji logiki biznesowej.

+0

powinieneś rozważyć użycie komentarza zamiast Odpowiedzi lub Przegłosowania, jeśli nie masz nic nowego do powiedzenia. –

Powiązane problemy