0

I have a .net 6.0 Blazor Server web application that is essentially a basic registration form (contact information: First Name, Last Name, Email, Phone, etc).

I'm trying to create a custom ValidationAttribute (EmailUniqueAttribute) that will check for uniqueness of the form's email field against the backend database. If it exists already IsValid returns false , else if it doesn't it returns true.

The problem I'm encountering is that it appears that you can only pass constant arguments into a custom ValidationAttribute? In this case the argument that would need to be used in the validation is a boolean value that is determined at runtime based on user input to the email field and the result of a database query to check for its existence (IsUnique).

I thought about injecting my service to the back end calls into the custom ValidationAttribute and checking for uniqueness at the time of validation (anti pattern debates aside) but it looks like support for DI into a ValidationAttribute isn't available until .Net 7.1 preview based on other articles and questions I've read on this topic here.

How exactly should I go about this?

bacis09
  • 109
  • 1
  • 8

1 Answers1

0

Well there are several ways to solve it:

A first one would be to setup the email-column inside your database with a unique constraint (you can do this for every solution/way). Duplicate entries will then throw an error on save. Simply catch the save-error and show them to your frontend.

Another way would be to handle errors a bit earlier by using the OnSubmit method of your EditForm. Inject a Service that reads all mail-entries from your database and check them against the entered email address. It should be sufficient to call the service once at OnInitialized to prevent multiple database selections for probably the same list.

A more convenient way for the user would be to use the above mentioned service to check the mail uniqueness while typing into the InputText field. You can hook up to several events there like @oninput.

You could also use some custom Validation packages like FluentValidation that extend the validation system by a more complex system which allows more complicated conditions to check against.

EDIT:

You can still make use of a custom attribute if desired:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
    public class EmailUniquenessAttribute : DataTypeAttribute
    {
        private EmailService _service;

        public EmailUniquenessAttribute() : base(DataType.EmailAddress)
        {
            // You can use your DI system to get the desired service here
            _service = new EmailService();
        }

        public override bool IsValid(object value)
        {
            if (value == null)
            {
                return true;
            }

            if (value is not string valueAsString)
            {
                return false;
            }

            return _service.EmailAlreadyExistsInDatabase(valueAsString);
        }
    }
DanielD
  • 326
  • 2
  • 7
  • "A more convenient way for the user would be to use the above mentioned service to check the mail uniqueness while typing into the InputText field. You can hook up to several events there like @oninput." I have this, the problem is that I want the validation message to fire off with the other messages on this field, such as the built in [Required] validator, I don't want to create secondary validation message control / element specifically for presenting this to the user, I want it to be included in the form validation for Email property on model bound to the form. – bacis09 Oct 04 '22 at 20:56
  • I've edited my answer to support the use of a custom attribute. There's also an option to use the EditContext and modify the error messages there (e.g. https://stackoverflow.com/questions/61892999/how-to-properly-manipulate-validation-messages-in-editcontext-with-blazor-server) – DanielD Oct 04 '22 at 21:01