2011-11-29 11 views
8

Mam dwa ViewModels (uproszczony):Walidacja zagnieżdżonych ViewModels

public class ParentViewModel 
{ 
    public ParentViewModel 
    { 
     Content = new ChildViewModel(); 
    } 

    public ChildViewModel Content { get; set, } 
} 

public class ChildViewModel 
{ 
    [Required] 
    public string Name1 { get; set, } 
    [Required] 
    public string Name2 { get; set, } 
} 

a następna akcja kontroler postu:

[HttpPost] 
public ActionResult Create(ParentViewModel viewModel) 
{ 
    if (ModelState.IsValid) 
    { 
     // process viewModel -> write something into database 
     return RedirectToAction("Index"); 
    } 
    return View(viewModel); 
} 

Teraz przesyłam następujące wartości formularza w ciele żądania POST do URL odpowiadające tej skargi (ręcznie w Fiddler żądanie Builder):

  • Content.Name1 = X

    Działa to dobrze, właściwość Name1 jest wypełnione viewModel.Content, Name2 jest null a państwo model jest nieważne, ponieważ Name2 jest wymagane. Tak więc sprawdzanie poprawności nie powiedzie się zgodnie z oczekiwaniami.

  • Xontent.Name1 = X lub Nazwa1 = X lub cokolwiek, tak że nic nie zostanie związana z viewModel

    Teraz viewModel.Content nie jest null (bo mam instancji go w konstruktorze), ale wszystko właściwości Name1 i Name2null. To jest oczekiwane. Co zrobiłem nie oczekiwać, że stan modelu jest ważne, więc przechodzi walidacji (prowadząc do wyjątków DB później, ponieważ istnieją nie-zerowalne kolumn).

Jak mogę poprawić ten kod tak, że walidacja działa również w drugim przypadku?

I tak trzech doświadczeniach

  • I Usunięto instancji z Content w konstruktora ParentViewModel, następnie Content jest null w drugim przykładzie powyżej, ale nadal przechodzi walidacji.

  • Dodałem atrybut do właściwości Content[Required] (ale nie usunąć konkretyzacji Content w konstruktorze ParentViewModel). Nie ma to żadnego efektu, opisane zachowanie obu powyższych testów jest takie samo.

  • I dodano atrybut [Required] do właściwości Contenti usunęła instancji z Content w konstruktora ParentViewModel. Wydaje się, że działa tak, jak chcę: W drugim teście Content jest null i sprawdzanie poprawności nie powiedzie się z powodu atrybutu [Required].to będzie wyglądać następująco:

    public class ParentViewModel 
    { 
        [Required] 
        public ChildViewModel Content { get; set, } 
    } 
    
    public class ChildViewModel 
    { 
        [Required] 
        public string Name1 { get; set, } 
        [Required] 
        public string Name2 { get; set, } 
    } 
    

chciałbym stwierdzić, że teraz instancji właściwość Content dzieci w konstruktorze ParentViewModel jest źródłem problemu i że sama spoiwo model musi instancji właściwości podrzędne (lub nie , jeśli nie ma pasujących pól formularza w żądaniu), aby mieć poprawnie działającą walidację po stronie serwera.

Mam instancję podrzędną właściwości w kilku innych konstruktorach modeli widoku i nie zauważyłem tego problemu do tej pory. Czy na ogół jest to zła praktyka? Czy istnieją inne sposoby rozwiązania problemu?

+0

Obecnie walczę z czymś podobnym. Jedyną różnicą w moim przypadku jest, że mam 'IEnountable' of ChildViewModels. Wypróbowałem wszystkie trzy powyższe opcje i żaden nie działa dla mnie. –

Odpowiedz

0

Trzecie rozwiązanie jest w porządku:

public class ParentViewModel 
{ 
    [Required] 
    public ChildViewModel Content { get; set, } 
} 

public class ChildViewModel 
{ 
    [Required] 
    public string Name1 { get; set, } 
    [Required] 
    public string Name2 { get; set, } 
} 

Używam go teraz w kilku miejscach i nie zauważy którykolwiek problemy.

0

ModelState.IsValid informuje, czy jakiekolwiek błędy modelu zostały dodane do ModelState.

Domyślny segregator modelu doda kilka błędów w przypadku problemów z konwersją typu podstawowego, takich jak przekazanie numeru innego niż coś, co jest "int". Możesz zapełnić modelState bardziej w oparciu o dowolny system sprawdzania poprawności, którego używasz. Sugerowałbym przeglądanie adnotacji danych w celu sprawdzania poprawności ViewModels, ponieważ działa dobrze.

Ta składnia może być niepoprawna lub stara. ModelState.AddModelError ("klucz", Exception)

sparafrazować z What is ModelState.IsValid valid for in ASP.NET MVC in NerdDinner?

+0

Widzę, że to * technicznie * alternatywa, ale * praktycznie * oznaczałoby to: W każdej akcji post z widokami modeli, które mają zagnieżdżone modele widoku, muszę zrobić coś takiego: 'if (viewModel.Content.Name1 == null && viewModel.Content.Name2 == null && ...) ModelState.AddModelError (...); 'To nie wygląda ładnie. W przypadku adnotacji danych: nie wiem, która z nich mogłaby mi pomóc. Używam już '[Wymagane]' i to wszystko, co walidacja powinna uwzględnić w moim modelu. Czy jest jakaś inna adnotacja "sztuczka"? – Slauma