2011-01-28 19 views
17

ho usato la convalida jQuery plug in per un paio di anni ormai, ma questo è il mio primo tentativo di miscelazione con MVC 3 convalida discreto.ASP .Net MVC 3 discreto personalizzato convalida del client

informazioni sul lato client delle cose è sparso tutti su Internet ed è difficile trovare qualsiasi cosa che è abbastanza in profondità per spiegarlo a persone che non hanno ancora utilizzato. Sto bruciando Google per un'ora per un esempio su come creare un validatore lato client personalizzato.

@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'); 
    }); 
}); 

se corro il codice di cui sopra nel fondo del mio punto di vista non fa assolutamente nulla. Ho anche provato jquery.validator.addmethod() e ancora niente. Tutte le convalide lato client emesse dalle annotazioni di convalida del modello funzionano correttamente.

<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

Hai incluso lo script "jquery.validate.unobtrusive.js" nella tua pagina? – Chandu

+0

sì ... tutte le altre opere di validazione lato client, nel mio modello devo fare alcune annotazioni campi richiesti e tutti funzionano bene. Voglio solo aggiungere un metodo di convalida personalizzato alla convalida del modulo. – JBeckton

risposta

26

Ecco come si potrebbe procedere. Innanzitutto è necessario scrivere un attributo validator personalizzato per garantire che la convalida venga applicata sul lato server. Si potrebbe utilizzare quello descritto in questo 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" 
     }; 
    } 
} 

Si noti che ho modificato per renderlo implementare l'interfaccia IClientValidatable e ha aggiunto il metodo GetClientValidationRules che utilizza semplicemente lo stesso messaggio di errore per la validazione client come il lato server e fornisce un nome univoco per questo validatore che verrà utilizzato dall'adattatore discreto di jQuery. Ora tutto quello che resta è quella di decorare la vostra proprietà modello con questo attributo:

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

e nella vista:

<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, grazie per la risposta dettagliata. Sto usando IValidatableObject nel mio modello piuttosto che gli attributi personalizzati vuol dire che non posso collegare la validazione lato server e client a meno che non utilizzi attributi personalizzati? – JBeckton

+0

Posso non aggiungere la convalida client personalizzata senza collegarla alla convalida lato server? – JBeckton

+1

@ JBeckton, si potrebbe ma sarebbe estremamente inutile e un'enorme vulnerabilità di sicurezza. Affinché ciò funzioni, è necessario disporre degli attributi HTML5 'dati- *' emessi nella propria casella di testo affinché l'adattatore funzioni. È necessario eseguire la logica di convalida almeno sul server. La convalida del lato client è solo a scopo cosmetico. –

2

È necessario ValidateFor oltre a TextBoxFor. Non posso dire dalla tua domanda se l'hai già fatto o no. È necessario anche EnableClientValidation prima del modulo.

+0

EnableClientValidation si trova nel mio web.config, ho rimosso gli aiutanti ValidatorFor perché non sono necessari con il nuovo MVC 3 validazione discreto. invece tutto ciò che serve è un elemento HTML con una classe di convalida sul campo valido – JBeckton

+1

Se non si dispone di 'ValidateFor', allora non sarà possibile visualizzare i messaggi di validazione lato server. In MVC 2, la convalida lato client non funzionerà anche senza di loro. –

+0

ok Ho capito, se js è disabilitato non vedrò i messaggi di validazione. Con è abilitato li vedo ma come messaggi val lato client. – JBeckton

Problemi correlati