Come sappiamo, Blazor supporta nativamente le data annotation per la validazione dei dati in input: grazie a questa funzionalità, possiamo per esempio decorare una classe User con attributi che ne specifichino i requisiti formali:
public class User { [Required] public string Username { get; set; } [RegularExpression(Constants.UK_PHONE_NUMBER)] public string MobilePhone { get; set; } [RegularExpression(Constants.UK_PHONE_NUMBER)] public string LandLinePhone { get; set; } }
A questo punto, è sufficiente aggiungere un DataAnnotationValidator (e magari anche un ValidationSummary) al componente EditForm, e il motore di rendering si occuperà automaticamente di verificarne la correttezza prima di procedere al submit:
<EditForm Model="this.NewUser" OnValidSubmit="this.SubmitAsync" class="col-6"> <DataAnnotationsValidator /> <ValidationSummary /> <div class="form-group"> <label>Username</label> <InputText class="form-control" @bind-Value="this.NewUser.Username" /> </div> <div class="form-group"> <label>Mobile Phone</label> <InputText class="form-control" @bind-Value="this.NewUser.MobilePhone" /> </div> <div class="form-group"> <label>Landline phone</label> <InputText class="form-control" @bind-Value="this.NewUser.LandLinePhone" /> </div> <button type="submit" class="btn btn-primary">Save</button> </EditForm> @Code { public User NewUser { get; set; } public async Task SubmitAsync() { // .. logica per memorizzare l'utente qui ... } }
Nel nostro caso, se provassimo a salvare uno user con dati errati, gli errori ci verrebbero evidenziati come in figura.
Purtroppo le data annotation funzionano bene con regole semplici, ma non sono idonee a rappresentare logiche di validazione più complesse, per esempio quelle che coinvolgono diverse proprietà.
Per questi scopi, una delle possibili soluzioni in Blazor è quella di costruire un custom validator. Immaginiamo di voler far sì che almeno uno tra Mobile Phone e Landline Phone sia obbligatorio. Possiamo implementare questa logica in una classe UserPhoneValidator simile alla seguente:
public class UserPhoneValidator : ComponentBase { private ValidationMessageStore _store; [CascadingParameter] public EditContext Context { get; set; } protected override void OnInitialized() { base.OnInitialized(); _store = new ValidationMessageStore(this.Context); this.Context.OnValidationRequested += Context_OnValidationRequested; ; this.Context.OnFieldChanged += Context_OnFieldChanged; } private void Context_OnValidationRequested(object sender, ValidationRequestedEventArgs e) { this.ExecuteValidation(); } private void Context_OnFieldChanged(object sender, FieldChangedEventArgs e) { if (e.FieldIdentifier.FieldName == "MobilePhone" || e.FieldIdentifier.FieldName == "LandLinePhone") { this.ExecuteValidation(); } } // .. altro codice qui .. }
La nostra classe eredita da ComponentBase, così che possiamo utilizzarla nel markup di Blazor, ed espone una proprietà di tipo EditContext. Si tratta di un CascadingParameter che viene automaticamente assegnato dalla form all'interno della quale poniamo il nostro componente, così che possiamo sia accederne al contenuto, sia ricevere una notifica al verificarsi di alcuni eventi.
Nel nostro caso, abbiamo sottoscritto gli eventi OnValidationRequested e OnFieldChanged, per eseguire la nostra logica sia al submit della form stessa, sia quando il valore di un field viene modificato. In quest'ultimo caso, come possiamo notare, ci preoccupiamo solo dei field relativi ai due numeri di telefono che vogliamo monitorare.
Il codice di ExecuteValidation è abbastanza semplice e sfrutta un ValidationMessageStore per inviare gli esiti della validazione alla form:
private void ExecuteValidation() { var model = (this.Context.Model as User); if (model == null) return; // this only works with User objects _store.Clear(); if (string.IsNullOrWhiteSpace(model.MobilePhone) && string.IsNullOrWhiteSpace(model.LandLinePhone)) { _store.Add(() => model.MobilePhone, "Either mobile or landline phone must be provided"); _store.Add(() => model.LandLinePhone, "Either mobile or landline phone must be provided"); } }
Come primo passo, puliamo lo store da eventuali messaggi precedenti. Poi, se entrambi i numeri di telefono sono vuoti, aggiungiamo una entry per ciascuno di queste due proprietà.
L'ultimo aspetto da non dimenticare è quello di implementare IDisposable, come in tutti i casi in cui sottoscriviamo eventi, per evitare memory leak:
public class UserPhoneValidator : ComponentBase, IDisposable { // .. altro codice qui .. public void Dispose() { this.Context.OnValidationRequested -= Context_OnValidationRequested; ; this.Context.OnFieldChanged -= Context_OnFieldChanged; } }
A questo punto, possiamo finalmente aggiungere il nostro validatore alla form in pagina:
<EditForm Model="this.NewUser" OnValidSubmit="this.Submit" class="col-6"> <DataAnnotationsValidator /> <UserPhoneValidator /> <ValidationSummary /> ... <button type="submit" class="btn btn-primary">Save</button> </EditForm>
Se abbiamo svolto tutti i passaggi correttamente, vedremo il messaggio di errore apparire contemporaneamente su entrambe le proprietà nel caso siano tutte e due vuote, e sparire nel momento in cui ne valorizziamo una.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Utilizzare QuickGrid di Blazor con Entity Framework
Sfruttare MQTT in cloud e in edge con Azure Event Grid
Assegnare un valore di default a un parametro di una lambda in C#
Utilizzare politiche di resiliency con Azure Container App
Implementare l'infinite scroll con QuickGrid in Blazor Server
Gestire liste di tipi semplici con Entity Framework Core
Utilizzare Copilot con Azure Cosmos DB
Creare una libreria CSS universale: Cards
Cancellare una run di un workflow di GitHub
Eseguire query manipolando le liste contenute in un oggetto mappato verso una colonna JSON
Inference di dati strutturati da testo con Semantic Kernel e ASP.NET Core Web API
.NET Conference Italia 2024
I più letti di oggi
- Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Utilizzare il metodo CountBy di LINQ per semplificare raggruppamenti e i conteggi
- Creare una libreria CSS universale: Cards
- Eseguire script pre e post esecuzione di un workflow di GitHub