2011-01-28 12 views
17

Używam wtyczki walidacyjnej jQuery od kilku lat, ale to jest mój pierwszy wysiłek, aby zmieszać się z dyskretną walidacją MVC 3.ASP .Net MVC 3 dyskretna, niestandardowa walidacja klienta

Informacje o stronie klienta są rozproszone po całym Internecie i trudno znaleźć coś, co wystarczyłoby do wyjaśnienia tego osobom, które go jeszcze nie używały. Od ponad godziny pracuję nad Google'em nad przykładem tworzenia niestandardowego walidatora po stronie klienta.

@Html.TextBoxFor(model => Model.CCPayment.CardNumber, new { @class = "textInput validateCreditCard", maxLength = "20" }) 

$(document).ready(function() { 
     jQuery.validator.unobtrusive.adapters.add('validateCreditCard', {}, function (value, element) { 
     alert('foo'); 
    }); 
}); 

Jeśli uruchomię powyższy kod w dolnej części mojego widoku, to absolutnie nic. Próbowałem nawet jquery.validator.addmethod() i nadal nic. Wszystkie walidacje po stronie klienta, które są emitowane z moich adnotacji sprawdzania poprawności modelu, działają poprawnie.

<div class="ctrlHolder"> 
       <label> 
        <em>*</em> 
        Card Number: 
       </label> 
       @Html.TextBoxFor(model => Model.CCPayment.CardNumber, new { @class = "textInput validateCreditCard", maxLength = "20" }) 

       <p class="field-validation-valid formHint" data-valmsg-for="CCPayment.CardNumber"></p> 
      </div> 
+0

Czy to skrypt „jquery.validate.unobtrusive.js” w swoją stronę? – Chandu

+0

tak ... działa sprawdzanie poprawności po stronie klienta, w moim modelu mam kilka adnotacji, które wymagają wypełnienia pól i wszystkie działają poprawnie. Po prostu chcę dodać niestandardową metodę sprawdzania poprawności do sprawdzania poprawności formularza. – JBeckton

Odpowiedz

26

Oto, jak można kontynuować. Najpierw musisz napisać niestandardowy atrybut sprawdzania poprawności, aby upewnić się, że sprawdzanie poprawności jest wymuszane po stronie serwera. Można użyć jednego opisanego w tym blog post:

public class CreditCardAttribute : ValidationAttribute, IClientValidatable 
{ 
    private CardType _cardTypes; 
    public CardType AcceptedCardTypes 
    { 
     get { return _cardTypes; } 
     set { _cardTypes = value; } 
    } 

    public CreditCardAttribute() 
    { 
     _cardTypes = CardType.All; 
    } 

    public CreditCardAttribute(CardType AcceptedCardTypes) 
    { 
     _cardTypes = AcceptedCardTypes; 
    } 

    public override bool IsValid(object value) 
    { 
     var number = Convert.ToString(value); 

     if (String.IsNullOrEmpty(number)) 
      return true; 

     return IsValidType(number, _cardTypes) && IsValidNumber(number); 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     return "The " + name + " field contains an invalid credit card number."; 
    } 

    public enum CardType 
    { 
     Unknown = 1, 
     Visa = 2, 
     MasterCard = 4, 
     Amex = 8, 
     Diners = 16, 

     All = CardType.Visa | CardType.MasterCard | CardType.Amex | CardType.Diners, 
     AllOrUnknown = CardType.Unknown | CardType.Visa | CardType.MasterCard | CardType.Amex | CardType.Diners 
    } 

    private bool IsValidType(string cardNumber, CardType cardType) 
    { 
     // Visa 
     if (Regex.IsMatch(cardNumber, "^(4)") 
      && ((cardType & CardType.Visa) != 0)) 
      return cardNumber.Length == 13 || cardNumber.Length == 16; 

     // MasterCard 
     if (Regex.IsMatch(cardNumber, "^(51|52|53|54|55)") 
      && ((cardType & CardType.MasterCard) != 0)) 
      return cardNumber.Length == 16; 

     // Amex 
     if (Regex.IsMatch(cardNumber, "^(34|37)") 
      && ((cardType & CardType.Amex) != 0)) 
      return cardNumber.Length == 15; 

     // Diners 
     if (Regex.IsMatch(cardNumber, "^(300|301|302|303|304|305|36|38)") 
      && ((cardType & CardType.Diners) != 0)) 
      return cardNumber.Length == 14; 

     //Unknown 
     if ((cardType & CardType.Unknown) != 0) 
      return true; 

     return false; 
    } 

    private bool IsValidNumber(string number) 
    { 
     int[] DELTAS = new int[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 0 }; 
     int checksum = 0; 
     char[] chars = number.ToCharArray(); 
     for (int i = chars.Length - 1; i > -1; i--) 
     { 
      int j = ((int)chars[i]) - 48; 
      checksum += j; 
      if (((i - chars.Length) % 2) == 0) 
       checksum += DELTAS[j]; 
     } 

     return ((checksum % 10) == 0); 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     yield return new ModelClientValidationRule 
     { 
      ErrorMessage = this.ErrorMessage, 
      ValidationType = "creditcard" 
     }; 
    } 
} 

Zauważ, że ja to zmodyfikowany, aby implementować interfejs IClientValidatable i dodatkową metodę GetClientValidationRules który po prostu wykorzystuje się ten sam komunikat o błędzie walidacji klienta jak po stronie serwera i zapewnia unikalną nazwę tego walidatora, który będzie używany przez dyskretny adapter jquery. Teraz wszystko, co pozostało jest ozdobić swoje właściwości modelu z tego atrybutu:

[CreditCard(ErrorMessage = "Please enter a valid credit card number")] 
[Required] 
public string CardNumber { get; set; } 

iw widoku:

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 
<script type="text/javascript"> 
    $(function() { 
     jQuery.validator.unobtrusive.adapters.addBool('creditcard'); 
    }); 
</script> 

@using (Html.BeginForm()) 
{ 
    @Html.TextBoxFor(x => x.CardNumber) 
    @Html.ValidationMessageFor(x => x.CardNumber) 
    <input type="submit" value="OK" /> 
} 
+0

Darin, dziękuję za szczegółową odpowiedź. Używam IValidatableObject w moim modelu zamiast niestandardowych atrybutów oznacza to, że nie mogę połączyć sprawdzania poprawności serwera i klienta, chyba że używam niestandardowych atrybutów? – JBeckton

+0

Czy nie można dodać sprawdzania klienta niestandardowego bez połączenia z weryfikacją po stronie serwera? – JBeckton

+1

@ JBeckton, mógłbyś, ale to byłoby bardzo bezużyteczne i ogromna luka w zabezpieczeniach. Aby to zadziałało, musisz mieć odpowiednie atrybuty 'data- *' HTML5 w twoim polu tekstowym, aby adapter działał. Powinieneś wykonać swoją logikę walidacji przynajmniej na serwerze. Walidacja po stronie klienta służy wyłącznie do celów kosmetycznych. –

2

Trzeba ValidateFor oprócz TextBoxFor. Nie mogę powiedzieć z twojego pytania, czy już to zrobiłeś, czy nie. Przed formularzem potrzebujesz też EnableClientValidation.

+0

EnableClientValidation jest ustawiona w moim pliku web.config, usunąłem pomocników ValidatorFor, ponieważ nie są one potrzebne z dyskretną walidacją mvc 3. zamiast tego potrzebny jest tylko element html z klasą sprawdzania poprawności w terenie. – JBeckton

+1

Jeśli nie masz 'ValidateFor', to nie zobaczysz komunikatów walidujących po stronie serwera. W MVC 2 sprawdzanie poprawności po stronie klienta również nie będzie działać bez nich. –

+0

ok Mam, jeśli js jest wyłączony, nie zobaczę wiadomości sprawdzania poprawności. Z włączoną jest widoczna, ale jako komunikaty val strony klienta. – JBeckton

Powiązane problemy