Radzen support fluentvalidation

Does Radzen support fluentvalidation?

We are not familiar with fluentvalidation and how it works - you can check our validator components if you need validation.

using System;
using FluentValidation.Results;
using Microsoft.AspNetCore.Components;

namespace Radzen.Blazor
{
    /// <summary>
    /// A validator component which compares a component value with a specified value.
    /// Must be placed inside a <see cref="RadzenTemplateForm{TItem}" />
    /// </summary> 
    /// </example>
    public class RadzenFluentValidator : ValidatorBase
    { 
        private ValidationResult validator;

        /// <summary>
        /// Gets or sets the message displayed when the component is invalid. Set to <c>"Value should match"</c> by default.
        /// </summary>
        [Parameter]
        public override string Text { get; set; } = "Value should match";

        /// <summary>
        /// Specifies the function which validates the component value. Must return <c>true</c> if the component is valid.
        /// </summary>
        [Parameter]
        public ValidationResult Validator
        {
            get => validator;
            set
            {
                validator = value;
                // If there is at least one error, override Text with the first error message
                if (validator?.Errors?.Any() == true)
                {
                    Text = string.Join(" ", validator.Errors.Select(e => e.ErrorMessage));
                }
                else 
                {
                    Text = "Value should match";
                }
            }
        }

        /// <inheritdoc />
        protected override bool Validate(IRadzenFormComponent component)
        { 
            return validator.IsValid;
        }
    }
}
1 Like

I think that is what I was looking for. But I'm not sure to understand how to use it.
I guess I have to put the RadzenFluentValidator like any other Radzen validator.
But when/where/how do I execute the FluentValidator and set the validation result in RadzenFluentValidator ?

Thanks for your message, it was not full code. Here is full example of use:

 <RadzenLabel Text="Name" />
 <RadzenTextBox @bind-Value="employee.Name" Name="Name" Style="width:100%" />
 <RadzenFluentValidator Component="Name" Popup="false" Validator="validator.ValidateSingle(employee, x => x.Name)" />

@code{
        private EmployeeDtoValidator validator = new ();
        private EmployeeDto employee = new ();
}
  public class EmployeeDtoValidator : BaseDtoValidator<EmployeeDto>
    {
        public EmployeeDtoValidator()
        {
            RuleFor(x => x.Name)
                .NameRule(); 
        }
    }
      public static class EmploteeDtoValidationExtensions
    {
        public static IRuleBuilderOptions<T, string> NameRule<T>(this IRuleBuilder<T, string> ruleBuilder)
        {
            return ruleBuilder
                .NotEmpty()
                .WithMessage("Name is required.")
                .MaximumLength(100)
                .WithMessage("Name must not exceed 100 characters.");
        }
}
public class EmployeeDto
{
    public string Name { get; set; }
}

   public class BaseDtoValidator<T> : AbstractValidator<T>
    {
        public ValidationResult ValidateSingle(
            T dto,
            Expression<Func<T, object>> propertySelector)
        {
            return this.Validate(dto, options => options.IncludeProperties(propertySelector));
        }
    }
1 Like

Thank you very much.

It's not yet totally working for me. Validation is triggered, the Text property in RadzenFluentValidator is set, but message is not displayed. I will debug to find out why.

Hi,

I've found why it doesn't work. Validate method is called before Validator is set.

I have made a few change to get it work. Here is my version of the validator :

public class RadzenFluentValidator : ValidatorBase
{
    private const string DefaultErrorMessage = "Value must match";
    
    [Parameter]
    public override string Text { get; set; } = DefaultErrorMessage;
    
    [Parameter, EditorRequired]
    public Func<ValidationResult> ValidationResult { get; set; } = () => new ValidationResult();

    /// <inheritdoc />
    protected override bool Validate(IRadzenFormComponent component)
    {
        ValidationResult result = ValidationResult();
        Text = result.Errors?.Count > 0 ? string.Join(" ", result.Errors.Select(e => e.ErrorMessage)) : DefaultErrorMessage;        
        return result.IsValid;
    }
}

and the call :

<RadzenFluentValidator Component="Name" ValidationResult="@(() => validator.ValidateSingle(model, x => x.Name))" />

And here is a generic version that avoids the need to specify the validation expression

public class RadzenFluentValidatorGeneric<TModel> : ValidatorBase
{
    private const string DefaultErrorMessage = "Value must match";
    
    [Parameter]
    public override string Text { get; set; } = DefaultErrorMessage;
    
    [Parameter, EditorRequired]
    public BaseValidator<TModel> FluentValidator { get; set; } = new();
    
    [Parameter, EditorRequired]
    public TModel Model { get; set; } = default!;
    
    [Parameter, EditorRequired]
    public Expression<Func<TModel, object>> PropertySelector { get; set; } = null!;

    protected override bool Validate(IRadzenFormComponent component)
    {
        ValidationResult result = FluentValidator.ValidateSingle(Model, PropertySelector);
        Text = result.Errors?.Count > 0 ? string.Join(" ", result.Errors.Select(e => e.ErrorMessage)) : DefaultErrorMessage;        
        return result.IsValid;
    }
}

the call :

<RadzenFluentValidatorGeneric Component="Name" Model="model" FluentValidator="validator" PropertySelector="x => x.Name" />
2 Likes