2010-12-20 10 views
6

Mam projekt ASP.NET MVC 2, w którym utworzyłem obiekt przesyłania danych w celu odbioru danych z formularza strony WWW. Formularz zawiera dwie grupy pól wyboru. Chcę zweryfikować obiekt, aby upewnić się, że zaznaczono co najmniej jedno z pól wyboru w każdej grupie.Walidator MVC środowiska ASP.NET, aby upewnić się, że przynajmniej jedno pole wyboru jest zaznaczone

Wykonuję sprawdzanie poprawności po stronie serwera, aby użytkownik nie mógł hackować po stronie sprawdzania poprawności po stronie klienta. (W późniejszym czasie dodam walidację po stronie klienta z jQuery, to proste.)

Rozumiem, że muszę utworzyć własną niestandardową ValidationAttribute dla mojej klasy obiektów transferu danych, ale nie rozumiem, jak tworzyć i używać taki, który może zaakceptować dowolną listę właściwości pola wyboru, aby upewnić się, że co najmniej jedna z nich jest prawdziwa. Domyślam będę musiał zadzwonić atrybuty tak:

[AtLeastOneCheckbox("set1check1", "set1check2", "set1check3", 
    ErrorMessage = "You must check at least one checkbox in set 1.")] 
[AtLeastOneCheckbox("set2check1", "set2check2", "set2check3", "set2check4", "set2check5", 
    ErrorMessage = "You must check at least one checkbox in set 2.")] 
public class MyFormDTO 
{ 
    ... 
} 

Co będzie realizacja AtLeastOneCheckboxAttribute wyglądać?

Czy istnieje inny sposób, w jaki powinienem przeprowadzić tego typu sprawdzanie poprawności?

+0

Ponadto, zastanawiam się, dlaczego Microsoft MVC pcha mnie do tego „atrybut” system walidacji dla wszystkiego. Jeśli używam sprawdzeń wykonanych przez atrybuty RequiredAttribute i StringLengthAttribute oraz inne atrybuty sprawdzania poprawności, umieszczam je na każdej właściwości, a następnie dodam do mojego obiektu metodę IsValid(), która wykonuje inne sprawdzenia właściwości tego obiektu, aby zdecydować, czy jest ona ważna, czy istnieje sposób, aby parametr ModelState odzwierciedlał wynik mojej metody IsValid()? –

Odpowiedz

4

jeśli masz kilka pól wyboru, wystarczy kilkakrotnie odznaczyć atrybut.

[AttributeUsage(AttributeTargets.Class)] 
public class AtLeastOneCheckboxAttribute : ValidationAttribute 
{ 
    private string[] _checkboxNames; 

    public AtLeastOneCheckboxAttribute(params string[] checkboxNames) 
    { 
     _checkboxNames = checkboxNames; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var propertyInfos = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) 
      .Where(x=>_checkboxNames.Contains(x.Name)); 

     var values = propertyInfos.Select(x => x.GetGetMethod().Invoke(value, null)); 
     if (values.Any(x => Convert.ToBoolean(x))) 
      return ValidationResult.Success; 
     else 
     { 
      ErrorMessage = "At least one checkbox must be selected"; 
      return new ValidationResult(ErrorMessage); 
     } 
    } 
} 

UPDATE

jak odkryli, walidacja poziomie klasy nazywa się dopiero po przechodzą wszystkie właściwości. Aby uzyskać błąd, po prostu użyj pustego ciągu jako klucza.

+0

Próbowałem użyć Twojego kodu, ale wydaje się, że nie jest on wywoływany. Ustawiam AtLeastOneCheckboxAttribute na moim obiekcie, a następnie sprawdzam ModelState w kontrolerze, ale metoda IsValid() tego atrybutu nigdy nie jest wywoływana, mimo że moje RequiredAttributes i StringLengthAttributes poprawnie generują komunikaty o błędach. Ponadto - w jaki sposób otrzymam wiadomość sprawdzania poprawności z mojego widoku? <% = Html.ValidationMessageFor (Model => Model.Set1Check1)%>, czy coś w tym stylu? –

+0

Rozwiązałem pierwszą połowę mojego pytania - najwyraźniej atrybuty na poziomie klasy nie są wywoływane, chyba że przechodzą wszystkie atrybuty na poziomie usługi. Moge z tym zyc. Ale nadal próbuję dowiedzieć się, jak wyświetlić komunikat o błędzie tego atrybutu w widoku ... –

+0

Wyświetl moją aktualizację. – Aliostad

0

Twój DTO, który zgaduję, że Twój ViewModel może ihert IDataErrorInfo. Następnie można wykonać walidację tak (uwaga nie skompilować ten)

//I'm guessing you have a list of checkboxes 
IEnumerable<bool> checkBoxes1; 
IEnumerable<bool> checkBoxes2; 

public class MyFormDTO : IDataErrorInfo 
{ 
    public string this[string prop] 
    { 
     get 
     { 
      if(prop == "checkBoxes1") 
      { 
       if(checkBoxes1.Any(x => x == true)) 
       { 
        return "Error: You need to select atleast one checkbox from set1"; 
       } 
      } 
      else if(prop == "checkBoxes2") 
      { 
       if(checkBoxes2.Any(x => x == true)) 
       { 
        return "Error: You need to select atleast one checkbox from set2"; 
       } 
      } 
      return null; 
     } 
    } 
    public string Error { get { return null; } } 
} 
Powiązane problemy