Blazor server side validation from business layer

Viewed 129

I successfully plugged FluentValidation in a simple Blazor application and everything works fine for basic validation.

Imagine we have this classes

public class Person
{
    public string Name { get; set; }
}

public class PersonValidator : AbstractValidator<Person>
{
    PersonValidator()
    {
        RuleFor(p => p.Name).NotEmpty();
    }
}

When I submit my form FluentValidation is doing it's job if the Name is empty.

My problem is that I have later another rule in my code for exemple Name must be unique in a database.

protected async Task HandleValidSubmit()
{
    try
    {
        SavePersonInDb(Person);
    }
    catch (NotUniqueException e)
    {
        // How to add a validation error to the Name property ?
    } 
}

I'm not sure how to add an error to the ModelState and return to the form page like in Razor Pages or traditional MVC.

1 Answers

Ok, I made some progress based on this blog post : https://www.learmoreseekmore.com/2021/01/blazor-server-forms-validator-component.html

I created this component

public class ServerSideValidator : ComponentBase
{
    private ValidationMessageStore _messageStore;

    [CascadingParameter]
    public EditContext CurrentEditContext { get; set; } = null!;

    protected override void OnInitialized()
    {
        if (CurrentEditContext == null)
        {
            throw new InvalidOperationException("To use validator component your razor page should have the edit component");
        }
        _messageStore = new ValidationMessageStore(CurrentEditContext);
        CurrentEditContext.OnValidationRequested += (s, e) => _messageStore.Clear();
        CurrentEditContext.OnFieldChanged += (s, e) => _messageStore.Clear(e.FieldIdentifier);
    }

    public void DisplayErrors(Dictionary<string, List<string>> errors)
    {
        foreach (var error in errors)
        {
            _messageStore.Add(CurrentEditContext.Field(error.Key), error.Value);
        }
        CurrentEditContext.NotifyValidationStateChanged();
    }
}

I have two validators now :

<EditForm Model="@Data" OnValidSubmit="@HandleValidSubmit">
    <FluentValidationValidator DisableAssemblyScanning="@true" />
    <ServerSideValidator @ref="serverSideValidator" />

</EditForm>

And I can add my custom error like this

protected async Task HandleValidSubmit()
{
    try
    {
        SavePersonInDb(Person);
    }
    catch (NotUniqueException e)
    {
        var errors = new Dictionary<string, List<string>>();
        errors.Add(nameof(Data.Description), new List<string> { "Testing description" });
        serverSideValidator.DisplayErrors(errors);
    } 
}

Now it works, but I'm wondering if there is a more elegant way to do it ?

Related