Publish New Official Blazor Package: FluentValidation.Blazor
See original GitHub issueSystem Details
- FluentValidation version: 8.5.0
- Web Framework version (eg ASP.NET Core 2.1, MVC 5, WebApi 2. Delete if not applicable): ASP.NET Core 3.0 Blazor
Issue Description
This is a plug-and-play, ready-to-use, tested component for automatically enabling FluentValidation
with ASP.NET Core 3.0 Blazor:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System;
using System.Collections.Generic;
namespace FluentValidation
{
/// <summary>
/// Add Fluent Validator support to an EditContext
/// </summary>
public class FluentValidator : ComponentBase
{
[CascadingParameter]
EditContext CurrentEditContext { get; set; }
[Inject]
IServiceProvider ServiceProvider { get; set; }
IValidator Validator { set; get; }
protected override void OnInitialized()
{
if (CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} " +
$"inside an EditForm.");
}
this.GetValidator();
this.AddValidation();
}
private void GetValidator()
{
var validatorType = typeof(IValidator<>);
var formType = CurrentEditContext.Model.GetType();
var formValidatorType = validatorType.MakeGenericType(formType);
this.Validator = ServiceProvider.GetService(formValidatorType) as IValidator;
if (this.Validator == null)
{
throw new InvalidOperationException($"FluentValidation.IValidator<{formType.FullName}> is"
+ " not registered in the application service provider.");
}
}
private void AddValidation()
{
var messages = new ValidationMessageStore(CurrentEditContext);
// Perform object-level validation on request
CurrentEditContext.OnValidationRequested +=
(sender, eventArgs) => ValidateModel((EditContext)sender, messages);
// Perform per-field validation on each field edit
CurrentEditContext.OnFieldChanged +=
(sender, eventArgs) => ValidateField(CurrentEditContext, messages, eventArgs.FieldIdentifier);
}
private void ValidateModel(EditContext editContext, ValidationMessageStore messages)
{
// ATTENTION: DO NOT USE Async Void + ValidateAsync
// Explanation: Blazor UI will get VERY BUGGY for some reason if you do that. (Field CSS lagged behind validation)
var validationResults = Validator.Validate(editContext.Model);
messages.Clear();
foreach (var error in validationResults.Errors)
{
var fieldID = editContext.Field(error.PropertyName);
messages.Add(fieldID, error.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
private void ValidateField(EditContext editContext, ValidationMessageStore messages, /*in*/ FieldIdentifier fieldIdentifier)
{
var vselector = new FluentValidation.Internal.MemberNameValidatorSelector(new[] { fieldIdentifier.FieldName });
var vctx = new ValidationContext(editContext.Model, new FluentValidation.Internal.PropertyChain(), vselector);
messages.Clear(fieldIdentifier);
var validationResults = Validator.Validate(vctx);
foreach (var error in validationResults.Errors)
{
var fieldID = editContext.Field(error.PropertyName);
messages.Add(fieldID, error.ErrorMessage);
}
editContext.NotifyValidationStateChanged();
}
}
}
Usage Tutorial
It’s very simple. It replaces built-in ASP.NET Core <DataAnnotationValidator>
Blazor Component without any additional settings in the codebase.
<EditForm Model="Form">
<FluentValidation.FluentValidator></FluentValidation.FluentValidator>
<div class="form-group">
<label for="name">Name</label>
<InputText id="name" class="form-control" @bind-Value="Form.Name"></InputText>
<ValidationMessage For="() => Form.Name"></ValidationMessage>
</div>
<div class="form-group">
<label for="email">Email</label>
<InputText id="email" type="email" class="form-control" @bind-Value="Form.Email"></InputText>
<ValidationMessage For="() => Form.Email"></ValidationMessage>
</div>
<div class="form-group">
<label for="phone_number">Phone Number</label>
<InputText id="phone_number" type="tel" class="form-control" @bind-Value="Form.PhoneNumber"></InputText>
<ValidationMessage For="() => Form.PhoneNumber"></ValidationMessage>
</div>
<div class="form-group">
<label for="password">Password</label>
<InputText id="password" type="password" class="form-control" @bind-Value="Form.Password"></InputText>
<ValidationMessage For="() => Form.Password"></ValidationMessage>
</div>
<div class="form-group">
<label for="password_verify">Verify Password</label>
<InputText id="password_verify" type="password" class="form-control" @bind-Value="Form.VerifyPassword"></InputText>
<ValidationMessage For="() => Form.VerifyPassword"></ValidationMessage>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">
<i class="fas fa-chevron-up"></i>
Submit
</button>
</div>
</EditForm>
The component will automatically grab registered IValidator<FormModelType>
from the DI, therefore library consumers will only need to register their validator implementation in the DI:
services.AddTransient<IValidator<CreateAccountFormModel>, CreateAccountFormModelValidator>();
Demo Screenshot
Automatic client-side validation. Excellent integration with custom validation.
Reference Implementation
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (2 by maintainers)
Top Results From Across the Web
Blazor — FluentValidation documentation
Built with Sphinx using a theme provided by Read the Docs. Read the Docs v: latest. Versions: latest.
Read more >Using FluentValidation for Forms Validation in Blazor
In this post, I'm going to show you how you can use the popular FluentValidation library, instead of data annotations, to validate the...
Read more >mrpmorris/blazor-validation
Blazor -Validation. Blazor-Validation is a validation agnostic library for validating forms in Blazor- Microsoft aspdotnet Blazor project.
Read more >Blazor Fluent Validation
On this episode of Blazor StateHasChanged() we explored validation using the FluentValidation package. Validation is still a concept in ...
Read more >Integrating FluentValidation with Blazor - Steve Sanderson
FluentValidation is a popular validation library for .NET Core by Jeremy Skinner. It has some advantages over .
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks for the suggestion. I am not planning on providing an official Blazor integration package for FluentValidation for a couple of reasons:
By including something like this in the project it’s making a commitment for me personally to support this code, write and maintain integration tests, write all the documentation, re-test everything whenever a new preview release comes out and commit to answering questions posted here about it. This is a massive cost to me. I already do all this for the asp.net integration and it’s exhausting - I’m afraid I don’t have the time (or inclination) to do this for blazor too.
This is the perfect opportunity for the community to step in and commit to maintain an integration package to ease the burden from me. I’d suggest you speak to @mrpmorris who is doing a great job on the blazor-fluentvalidation package at https://github.com/mrpmorris/blazor-validation. If you want to help, I would recommend you head over there and see if there’s anything you can get involved in.
Thanks for understanding.
Sorry, I don’t understand what you mean
The CSS class on Inputs not updating is a known bug in Blazor.
Blazor-Validation allows you to have multiple validation approaches for the same app. So you could have
DataAnnotationsValidator
andFluentValidationValidator
validating the form at the same time simply by adding a simple<Validate/>
component. It is changed throughout the app with a single line of code, which discovers validators for you.I don’t know what you mean by this either.