Is it possible to validate a property using data-annotation asynchronously with ASP.NET Core?

Viewed 579

I have an asp.net core 3.1 based project. I need to add a custom validation rule that will require a database call in ordered to determine the validity of the value.

For example, when creating a new user, I need to validate that there is no other username in the database with the same username before allowing the user to be created.

If I can create a custom attribute UniqueUsername, then I should be able to do something like this

public class UniqueUsername : ValidationAttribute
{
    private readonly UserManager _manager = manager;

    public UniqueUsername (UserManager manager)
    {
       _manager = manager;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string username = value.ToString();

        if(_manager.Exists(username)) 
        {
             return new ValidationResult("The username provided belong to a different user.");
        }
        return ValidationResult.Success;
    }
}

But, _manager.Exists(username) is a synchronous call. I want to avoid blocking the main thread, so I want a way to call await _manager.ExistsAsync(username) instead to avoid blocking the main thread.

Is there a way to create an attribute that would validate a single property and write errors "if any" to the ModelState?

If this isn't possible using data-annotation, is there an different way to validate property while writting errors to ModelState so when ModelState.IsValid() or TryValidateModel(model) are called, the attribute is called?

1 Answers

The data-annotations you add in your model are meant to validate the data present within the model (although some can also be translated into your database). These are meant to be reused even if you were to use your models on a client framework.

You can use the ModelState functions you mentioned to make async calls to your database. If you want to remove the logic from your controller, you can create utility functions to do so.

If you are open to third-party libraries, there is a great and popular validations library called Fluent Validation. Here is a documentation on how you can make async calls with it: https://docs.fluentvalidation.net/en/latest/async.html

Related