Home > database >  Fluent Validation - Check for Duplicate Value
Fluent Validation - Check for Duplicate Value

Time:07-25

I have a EditForm in a Blazor Server application and i want to check if an InputText value is in a list. How can i pass the list to compare from my UI to the Validator class for comparison?

I have tried comparing the @bind-Value in line and encapsulating the validation message but it skips over the validation message when the encapsulating function tests true.

 <EditForm Model="@resourceToBeCreated">
    <FluentValidationValidator ValidatorType=typeof(ResourceValidator)/>
    @if (resourcesSortedCollection.FirstOrDefault(x => x.Name == resourceToBeCreated.Name) != null)
    {
        <CustomValidationMessage For="() => resourceToBeCreated.Name" /> 
    }
                             
    <InputTextOnInput @bind-Value="@resourceToBeCreated.Name"   placeholder="Name..." />
 </EditForm>

I can obviously do this or something similar in the @code section but i dont get the validation popup on inupt.

So the question is, how can i pass this list to the Validator class for comparison?

EDIT: InputTextOnInput component:

@inherits InputText
<input @attributes="AdditionalAttributes"
       
       value="@CurrentValue"
       @oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />

CodePudding user response:

First an inherited InputText control. This overrides TryParseValueFromString and does the validation there.

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;

namespace BlazorApp1.Pages;

public class InputTextValidated : InputText
{
    [Parameter, EditorRequired] public IEnumerable<string>? CheckList { get; set; }
 { get; set; }

    protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage)
    {
        result = null;
        validationErrorMessage = null;

        var isValid = this.CheckList is not null
            && this.CheckList.Any(item => item.Equals(value, StringComparison.InvariantCultureIgnoreCase));

        if (isValid)
            result = value;
        else
            validationErrorMessage = "You must enter a value in the validation list";

        return isValid;
    }
}

And a test page:

@page "/"

<PageTitle>Index</PageTitle>

<EditForm Model=this.model>
    <DataAnnotationsValidator />
    <InputTextValidated  CheckList=Countries @bind-Value="@this.model.Country" />
    <ValidationSummary />
</EditForm>

<div>
    Country : @model.Country
</div>

@code {
    private DataModel model = new DataModel();

    private List<string> Countries = new List<string> { "UK", "Spain" };

    public class DataModel
    {
        public string? Country;
    }
}

As an alternative you could use/build an Input List control.

How Validation works

Validation data is held in ValidationMessageStore's associated with an EditContext. A ValidationMessageStore is a composite collection of key/value pairs:

  • the field defined as a FieldIdentifier [the model as an object and the field name as a string]
  • the validation message as string.

Each validation provider has it's own message store and can clear and add messages to it. It only has write/delete access to it's own message store. Providers get the EditContext cascaded by the EditForm, create a message store associated with the EditContext and logs messages to and clears messages from that store. FluentValidationValidator, DataAnnotationsValidator, any InputBase control or classes you write that interact with the EditContext are providers with message stores associated with the EditContext.

ValidationSummary and ValidationMessage are consumers. They interact with the message stores associated with a EditContext via the cascaded EditContext. All the messages are available as read only. ValidationMessage constructs a FieldIdentifier from the For expression to filter the messages.

  • Related