2009-10-13 14 views
27

Sto utilizzando la convalida Data Annotation in modo esteso in ASP.NET MVC 2. Questa nuova funzione è stata un enorme risparmio di tempo, poiché ora sono in grado di definire la convalida lato client e la convalida lato server in un'unica posizione. Tuttavia, mentre stavo facendo alcuni test dettagliati, mi sono reso conto che è abbastanza facile per qualcuno aggirare la convalida lato server se facevo affidamento solo sulla convalida Data Annotation. Ad esempio, se ho definito un campo obbligatorio annotando la proprietà con l'attributo [Richiesto] e inserito una casella di testo per quel campo obbligatorio in un modulo, un utente potrebbe semplicemente rimuovere la casella di testo dal DOM (che può essere facilmente eseguita tramite Firebug) e ora la convalida Annotazione dei dati non verrà attivata su quella proprietà durante il ModelBinding all'interno di un Controller. Per garantire che venga attivata la convalida "richiesta", posso ripetere la convalida dopo il verificarsi di ModelBinding, ma in tal caso dovrei ripetere la logica di convalida.ASP.NET MVC: la convalida dell'annotazione dei dati è sufficiente?

Qual è la raccomandazione di tutti sulla convalida? La convalida dell'annotazione dei dati è sufficiente? Oppure la convalida deve essere ripetuta per garantire che le convalide vengano attivate in tutte le situazioni?

Follow-up commento: Sulla base delle risposte qui sotto, sembra che non posso contare sulla convalida del modello Binder e dati di annotazione da solo. Poiché stiamo concludendo che è necessaria una convalida aggiuntiva lato server, esiste un modo semplice per il mio livello di servizio di attivare la convalida in base a quanto definito nelle Annotazioni dei dati? Sembra che questo ci porterà il meglio di entrambe le parole ... non sarà necessario ripetere il codice di convalida, ma ci assicureremo comunque che la convalida venga eseguita anche se Model Binder non lo attiva.

Ho intenzione di postare questo commento di follow-up come una domanda separata, in quanto pone una domanda diversa da quella originale.

+0

risposta del Koritnik risponde alla tua domanda di follow-up. Faccio la mia convalida in modo simile alla risposta che ha pubblicato. La stessa definizione DataAnnotation può essere utilizzata per la convalida sia del server che del client. –

+1

La convalida dell'annotazione dei dati va bene se gli attributi di convalida forniti e il framework stesso sono adatti a te. Il comportamento con Richiesto è stato modificato per ASP.NET MVC 2 RTM a causa del feedback della comunità, quindi [Richiesto] ora funziona come ci si aspetterebbe. Optinally, check out: Validation Block (Enterprise Library), xVal, NHibernate Validators (presumibilmente non ha alcuna dipendenza da NHibernate ORM). – miha

+0

'" Ho intenzione di postare questo commento di follow-up come una domanda separata, in quanto pone una domanda diversa da quella originale. "" Un collegamento a questa non sarebbe una cattiva idea, eh? – Sinjai

risposta

18

penso di essere vigili in materia di sicurezza si dovrebbe scegliere a te rendere prioritaria la convalida del server e assicurarti che questa sia sempre la tua riserva. La convalida del server dovrebbe funzionare senza la convalida del client. La validazione del client è più per UX e quindi è fondamentale per la progettazione, è secondaria alla sicurezza. Con questo in mente ti ritrovi a ripetere la tua convalida. Spesso si cerca di progettare l'app in modo tale che la convalida del server e del client possa essere integrata il più possibile per ridurre il lavoro richiesto per la convalida sul server e sul client. Ma ti assicuriamo che devi fare entrambe le cose.

Se bypassando la convalida del client (tramite manipolazione DOM) si evita la convalida del server (che sembra si stia indicando), allora la convalida del server per questa istanza potrebbe non essere utilizzata in modo appropriato. Dovresti invocare di nuovo la convalida del server nell'azione del controller o in un livello di servizio. Lo scenario che descrivi non dovrebbe sconfiggere la convalida del tuo server.

Con lo scenario descritto, il metodo degli attributi DataAnnotation dovrebbe essere sufficiente. Sembra che sia sufficiente apportare alcune modifiche al codice per garantire che la convalida del server venga invocata anche durante l'invio del modulo.

2

Il DataAnnotation non è certamente sufficiente. Lo uso estesamente anche per pre-validare le mie chiamate al modello di dominio per ottenere una migliore segnalazione degli errori e fallire il prima possibile.

È tuttavia possibile modificare personalmente il modello DataAnnotation per garantire che le proprietà con [Required] DEVONO essere pubblicate. (Seguirà il codice più tardi oggi).

UPDATE Ottenere la fonte per DataAnnotations modello Binder e trovare questa linea in DataAnnotationsModelBinder.cs

// Only bind properties that are part of the request 
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) { 

Change a

// Only bind properties that are part of the request 
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey); 
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0; 
if (contextHasKey || (!contextHasKey && isRequired)) { 
+0

Grazie Martijn. Non vedo l'ora di vedere il tuo codice. –

+0

Certo, ho postato questo prima di andare al lavoro (al lavoro ancora adesso) quindi non ho tempo per codificare :(. Ho modificato il raccoglitore prima leggermente perché non controllava gli oggetti nidificati e reimpostato le proprietà non valide su null che non ero d'accordo con vedere http://stackoverflow.com/questions/820468/how-does-dataannotationsmodelbinder-work-with-custom-viewmodels/864541#864541 Ho aggiunto anche i controlli richiesti da allora ma vorrei testarli quando arrivo a casa prima –

+0

Aggiornato con il codice, ma non sono nella posizione di testarlo correttamente lo farò di nuovo domani ma lo ho postato in modo forse è possibile valutarlo più velocemente.Fa superato i test unitari del progetto ma per essere onesti lì non è un test che prova questo caso: D –

7

Ho accoppiato xVal con DataAnnotations e ho scritto il mio filtro Action che controlla qualsiasi parametro di tipo Entity ai fini della convalida. Quindi, se nel postback manca del campo, questo validatore riempirà il dizionario ModelState e quindi avrà un modello non valido.

Prerequisiti:

  • mio soggetto/modello di tutti gli oggetti implementano IObjectValidator un'interfaccia che dichiara Validate() metodo.
  • mia classe attributo viene chiamato ValidateBusinessObjectAttribute
  • convalida xVal biblioteca

codice del filtro Azione:

public void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator); 
    foreach (KeyValuePair<string, object> param in parameters) 
    { 
     object value; 
     if ((value = param.Value) != null) 
     { 
      IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate(); 
      if (errors.Any()) 
      { 
       new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key); 
      } 
     } 
    } 
} 

La mia azione di controllo è definita come questo allora:

[ValidateBusinessObject] 
public ActionResult Register(User user, Company company, RegistrationData registrationData) 
{ 
    if (!this.ModelState.IsValid) 
    { 
     return View(); 
    } 
    ... 
} 
+0

hai un esempio più dettagliato su come utilizzare questo o un progetto scaricabile forse –

+0

@geocine: dove sembra essere il problema? Stai usando MVC1? Le versioni più recenti non richiedono questo, perché convalidano automaticamente i parametri di tipo forte ... Ma questo esempio qui è tanto dettagliato quanto dovrebbe essere nella realtà. Quindi dove sembra essere il problema? –

+0

Sono appena passato e sono nuovo ad aspmvc a leggere i problemi di convalida. Ho dimenticato che stavo usando MVC 2. il mio male. –

2

ho scritto il mio ValidationService per MVC 1.0 copiando i modelli da entrambi i xV Al's DataAnnotationsRuleProvider e Microsoft's DataAnnotationsModelBinder (e commenti di Martijn). L'interfaccia di servizio è qui sotto:

public interface IValidationService 
{ 
    void Validate(object instance); 

    IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

public abstract class BaseValidationService : IValidationService 
{ 
    public void Validate(object instance) 
    { 
     var errors = GetErrors(instance); 

     if (errors.Any()) 
      throw new RulesException(errors); 
    } 

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance); 
} 

il servizio è un corridore convalida che cammina l'albero struttura dell'istanza dell'oggetto che riceve e esegue effettivamente attributi convalida che trovi su ogni proprietà, creazione di un elenco di oggetti ErrorInfo quando gli attributi non sono validi (Pubblicherei l'intera fonte ma è stata scritta per un cliente e non so ancora se sono autorizzato a farlo.)

È quindi possibile fare in modo che i controller, i servizi di business logic richiamino esplicitamente la convalida quando sei pronto, invece di affidarti esclusivamente al modello di binder per la convalida.

ci sono un paio di altre insidie ​​che si dovrebbe essere a conoscenza di:

  • L'impostazione predefinita DataTypeAttribute nei dati annotazioni non effettivamente fare qualsiasi tipo di convalida dei dati , quindi avrai bisogno di scrivere un nuovo attributo che utilizza effettivamente xVal regolari espressioni (o altro) a eseguire la convalida del tipo di dati lato server .
  • xVal non cammina oggetti da creare sul lato client convalida, quindi si consiglia di fare alcune modifiche lì per ottenere più robusto convalida lato client.

Se sono autorizzato e ho tempo, cercherò di rendere disponibile più sorgente ...

1

See CodeProject Server-side Input Validation using Data Annotations

convalida di ingresso può essere eseguita automaticamente sul lato client in ASP.NET MVC o la convalida in modo esplicito il modello contro le regole. Questo suggerimento descriverà come può essere eseguito manualmente sul lato server di un'applicazione ASP.NET o all'interno del codice di repository delle applicazioni WPF .

 // Use the ValidationContext to validate the Product model against the product data annotations 
     // before saving it to the database 
     var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null); 
     var validationResults = new List<ValidationResult>(); 

     var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true); 
Problemi correlati