Le DataAnnotation sono un sistema standard, nel .NET Framework, per esprimere regole validazione tramite una sintassi basata su attributi. I diversi modelli di sviluppo che oggi abbiamo a disposizione, ad esempio ASP.NET Dynamic Data Controls o ASP.NET MVC (dalla versione 2), sono in grado poi di interpretare questo codice dichiarativo, applicando le varie regole per determinare se l'input dell'utente sia valido o meno.
In ASP.NET MVC, ad esempio, è sufficiente decorare il model User come segue
public class User { [Required] public string Username { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } [Required] [DataType(DataType.Password)] [Compare("Password")] public string ConfirmPassword { get; set; } }
e successivamente interrogare la proprietà ModelState.IsValid, per far sì che il framework verifichi che:
- tutte le proprietà siano popolate, visto che tutte sono marcate come Required;
- il contenuto dell proprietà ConfirmPassword corrisponda a quello di Password, come specificato dall'attributo Compare.
La più grande potenzialità delle DataAnnotation è però costituita dalla possibilità di realizzare attributi personalizzati per implementare le proprie regole di validazione. Supponiamo ad esempio che, per ragioni di sicurezza, vogliamo fare in modo che la password contenga almeno uno tra alcuni simboli specificati. Per questi scopi può sicuramente tornare utile l'attributo RegularExpressionAttribute, che effettua una validazione in base ad una regular expression fornita come parametro. Alternativamente, però, volendo avvalersi di una sintassi più semplice, possiamo pensare di realizzarne una nostra versione, così che possiamo sfruttarla in maniera simile alla seguente:
[Required] [MustContain("!£$%")] [DataType(DataType.Password)] public string Password { get; set; }
Per raggiungere questo scopo è sufficiente creare una classe che erediti da ValidationAttribute, come nell'esempio:
public class MustContainAttribute : ValidationAttribute { public string Chars { get; set; } public MustContainAttribute(string chars) // Messaggio di default : base("Il campo {0} deve contenere almeno un carattere tra {1}") { this.Chars = chars; } }
Essa definisce una proprietà Chars, inizializzata tramite il costruttore, che utilizzeremo per memorizzare l'elenco dei caratteri richiesti. La regola di validazione vera e propria, invece, può essere implementata effettuando l'override del metodo IsValid:
protected override ValidationResult IsValid( object value, ValidationContext validationContext) { var stringValue = value as string; if (stringValue.Any(c => Chars.Contains(c))) return null; return new ValidationResult( this.FormatErrorMessage(validationContext.DisplayName)); }
Questo metodo riceve in ingresso un parametro value, che contiene il dato che dobbiamo validare, più un ValidationContext tramite cui possiamo reperire, se necessarie, ulteriori informazioni relative all'operazione di validazione in atto, come l'istanza completa dell'oggetto o il nome della proprietà validata. La logica del metodo è molto semplice, e si limita a verificare, tramite l'extension method Any di LINQ, la presenza all'interno della stringa in input di almeno uno dei caratteri di Chars.
Nel caso la validazione fallisca, viene restituita un'istanza di ValidationResult contenente il messaggio d'errore. Quest'ultimo può essere eventalmente personalizzato effettuando l'override del metodo FormatErrorMessage, includendo ad esempio l'elenco dei caratteri richiesti oltre al nome della proprietà errata.
public override string FormatErrorMessage(string name) { return string.Format(this.ErrorMessageString, name, Chars); }
L'implementazione in alto, in particolare, genera il messaggio di errore utilizzando come template la proprietà ErrorMessageString. Essa, infatti, viene automaticamente popolata dalla classe base in base al valore di ErrorMessage, ErrorMessageResourceName ed ErrorMessageResourceType, se definiti dall'utente.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Mascherare l'output di un valore all'interno dei log di un workflow di GitHub
Hosting di componenti WebAssembly in un'applicazione Blazor static
Trasformare qualsiasi backend in un servizio GraphQL con Azure API Management
Short-circuiting della Pipeline in ASP.NET Core
Eseguire query manipolando le liste contenute in un oggetto mappato verso una colonna JSON
Modificare i metadati nell'head dell'HTML di una Blazor Web App
Effettuare chiamate con versioning da Blazor ad ASP.NET Core
Gestire undefined e partial nelle reactive forms di Angular
C# 12: Cosa c'è di nuovo e interessante
Effettuare il binding di date in Blazor
Reactive form tipizzati con FormBuilder in Angular
Effettuare il deploy di immagini solo da container registry approvati in Kubernetes
I più letti di oggi
- Miglioramenti nelle performance di Angular 16
- Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
- HTML5 con CSS e JavaScript
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Ottimizzazione dei block template in Angular 17
- Disabilitare automaticamente un workflow di GitHub (parte 2)