2013-09-02 8 views
23

Come è il modo migliore per convalidare un modello in MVC.Net dove voglio accettare un minimo/massimo.Convalida MVC inferiore/superiore a un altro valore

Non singoli valori min/max per un campo. Ma campi separati per un utente per specificare un minimo/massimo.

public class FinanceModel{ 
    public int MinimumCost {get;set;} 
    public int MaximumCost {get;set;} 
} 

Quindi ho bisogno di garantire che MinimumCost è sempre inferiore al costo massimo.

risposta

21

È possibile utilizzare un attributo di convalida personalizzato qui è il mio esempio con le date. Ma puoi usarlo anche con int.

primo luogo, qui è il modello:

public DateTime Beggining { get; set; } 

    [IsDateAfterAttribute("Beggining", true, ErrorMessageResourceType = typeof(LocalizationHelper), ErrorMessageResourceName = "PeriodErrorMessage")] 
    public DateTime End { get; set; } 

E qui è l'attributo stesso:

public sealed class IsDateAfterAttribute : ValidationAttribute, IClientValidatable 
{ 
    private readonly string testedPropertyName; 
    private readonly bool allowEqualDates; 

    public IsDateAfterAttribute(string testedPropertyName, bool allowEqualDates = false) 
    { 
     this.testedPropertyName = testedPropertyName; 
     this.allowEqualDates = allowEqualDates; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName); 
     if (propertyTestedInfo == null) 
     { 
      return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName)); 
     } 

     var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null); 

     if (value == null || !(value is DateTime)) 
     { 
      return ValidationResult.Success; 
     } 

     if (propertyTestedValue == null || !(propertyTestedValue is DateTime)) 
     { 
      return ValidationResult.Success; 
     } 

     // Compare values 
     if ((DateTime)value >= (DateTime)propertyTestedValue) 
     { 
      if (this.allowEqualDates && value == propertyTestedValue) 
      { 
       return ValidationResult.Success; 
      } 
      else if ((DateTime)value > (DateTime)propertyTestedValue) 
      { 
       return ValidationResult.Success; 
      } 
     } 

     return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ErrorMessage = this.ErrorMessageString, 
      ValidationType = "isdateafter" 
     }; 
     rule.ValidationParameters["propertytested"] = this.testedPropertyName; 
     rule.ValidationParameters["allowequaldates"] = this.allowEqualDates; 
     yield return rule; 
    } 
+7

È necessario completare questo esempio con la validazione lato client: 'jQuery.validator.addMethod ('isdateafter', la funzione (valore, elemento, params) { if (!/Invalid | NaN/.test (new Date (value))) { return new Date (value)> new Date(); } return isNaN (valore) && isNaN ($ (params) .val()) || (parseFloat (valore)> parseFloat ($ (params) .val())); }, ''); jQuery.validator.unobtrusive.adapters.add ('isdateafter', {}, funzione (opzioni) { options.rules [ 'isdateafter'] = true; options.messages [ 'isdateafter'] = options.message; }); ' – LoBo

+0

Sembra che ci sia un bug a causa della riga' if (this.allowEqualDates && value == propertyTestedValue) '. Funziona: 'if (this.allowEqualDates && value.Equals (propertyTestedValue))' o anche questo 'if (this.allowEqualDates && (DateTime) value == (DateTime) propertyTestedValue)'. – publicgk

26

Esiste un pacchetto chiamato NuGet Foolproof che prevede queste annotazioni per voi. Detto questo, la scrittura di un attributo personalizzato è alquanto semplice e buona pratica.

Utilizzando infallibile sarebbe simile:

public class FinanceModel{ 
    public int MinimumCost {get;set;} 

    [GreaterThan("MinimumCost")] 
    public int MaximumCost {get;set;} 
} 
+1

Accettato il validatore personalizzato solo come strumento di apprendimento. Grazie per il riferimento a Foolproof. Lo manterrà a portata di mano solo in caso contrario. –

+0

Foolproof non sembra accettare messaggi di errore personalizzati. –

+2

I messaggi di errore personalizzati vengono specificati come tali [GreaterThan ("MinimumCost"), ErrorMessage = "Deve essere maggiore del costo minimo"] –

-7

Perché non siete abituati Gamma Validator. Sintassi:

[Range(typeof(int), "0", "100", ErrorMessage = "{0} can only be between {1} and {2}")] 
    public int Percentage { get; set; } 
+2

Se guardi la mia domanda originale o le risposte esistenti, vedrai la situazione che sto cercando di convalidare è dove un utente può selezionare limiti superiore/inferiore. Non quando devono inserire un valore tra i valori alto/basso esistenti. –

6

Per la validazione lato client utilizzando i allowEqualDates e parametri propertyTested (complemento a Boranas risposta precedente ma troppo lungo per un commento):

// definition for the isdateafter validation rule 
if ($.validator && $.validator.unobtrusive) { 
    $.validator.addMethod('isdateafter', function (value, element, params) { 
     value = Date.parse(value); 
     var otherDate = Date.parse($(params.compareTo).val()); 
     if (isNaN(value) || isNaN(otherDate)) 
      return true; 
     return value > otherDate || (value == otherDate && params.allowEqualDates); 
    }); 
    $.validator.unobtrusive.adapters.add('isdateafter', ['propertytested', 'allowequaldates'], function (options) { 
     options.rules['isdateafter'] = { 
      'allowEqualDates': options.params['allowequaldates'], 
      'compareTo': '#' + options.params['propertytested'] 
     }; 
     options.messages['isdateafter'] = options.message; 
    }); 
} 

Maggiori informazioni: unobtrusive validation, jquery validation

1

In VB per numeri interi:

MODELLO

<UtilController.IsIntegerGreatherOrEqualThan("PropertyNameNumberBegins", "PeriodErrorMessage")> 
     Public Property PropertyNameNumberEnds As Nullable(Of Integer) 

CONVALIDA

Public Class IsIntegerGreatherOrEqualThan 
     Inherits ValidationAttribute 

     Private otherPropertyName As String 
     Private errorMessage As String 

     Public Sub New(ByVal otherPropertyName As String, ByVal errorMessage As String) 
      Me.otherPropertyName = otherPropertyName 
      Me.errorMessage = errorMessage 
     End Sub 

     Protected Overrides Function IsValid(thisPropertyValue As Object, validationContext As ValidationContext) As ValidationResult 

      Dim otherPropertyTestedInfo = validationContext.ObjectType.GetProperty(Me.otherPropertyName) 

      If (otherPropertyTestedInfo Is Nothing) Then 
       Return New ValidationResult(String.Format("unknown property {0}", Me.otherPropertyName)) 
      End If 

      Dim otherPropertyTestedValue = otherPropertyTestedInfo.GetValue(validationContext.ObjectInstance, Nothing) 

      If (thisPropertyValue Is Nothing) Then 
       Return ValidationResult.Success 
      End If 

      '' Compare values 
      If (CType(thisPropertyValue, Integer) >= CType(otherPropertyTestedValue, Integer)) Then 
       Return ValidationResult.Success 
      End If 

      '' Wrong 
      Return New ValidationResult(errorMessage) 
     End Function 
    End Class 
+0

Ho rimosso "FormatErrorMessage" dal codice mentre aggiungeva "'Il campo' + {errorMessage} + 'non è valido'". Stavo facendo un controllo sulla data, quindi ho sostituito Integer con Date. Ha funzionato alla grande e mi ha fatto risparmiare tempo. Grazie. – PHBeagle

+0

Quindi errorMessage stava visualizzando un messaggio sbagliato ?, quando l'ho usato non ho prestato attenzione per questo. – Dani

+0

Non proprio sbagliato, solo una formulazione extra. Usando "Restituisci nuovo ValidationResult (errorMessage)" allora era buono. – PHBeagle

Problemi correlati