Berk KARASU
Berk KARASU

Reputation: 71

I can't use fluent validation on all points

I used the fluentvalidation library to create validations for my viewmodels. The validation messages I wrote are valid at some points, and at some points they are crushed under another message. I searched how to solve this but couldn't find a definitive solution.

ViewModel

   public class SignUpViewModel
    {
        public string UserName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }

    }

Validation

 public class SignUpVMValidator : AbstractValidator<SignUpViewModel>
    {
        public SignUpVMValidator()
        {
            RuleFor(x => x.UserName)
                .NotNull().WithMessage("Kullanıcı Adı Boş Bırakılamaz")
                .MinimumLength(6).WithMessage("Kullanıcı Adı Minimum 6 Karakterden Oluşmalıdır")
                .MaximumLength(20).WithMessage("Kullanıcı Adı Maksimum 20 Karakterden Oluşmalıdır");

            RuleFor(x => x.Password)
                .MinimumLength(6).WithMessage("Şifre Minimum 6 Karakterden Oluşmalıdır")
                .MaximumLength(20).WithMessage("Şifre Maksimum 20 Karakterden Oluşmalıdır")
                .NotNull().WithMessage("Şifre Boş Bırakılamaz").NotEmpty().WithMessage("Şifre Boş Bırakılamaz");

            RuleFor(x => x.Email)
                .NotNull().WithMessage("Email Boş Bırakılamaz")
                .EmailAddress();
        }
    }

Controller

[HttpPost]
    public async Task<IActionResult> Index(SignUpViewModel signUpViewModel)
    {
        if (ModelState.IsValid)
        {
            AppUser user = signUpViewModel.Adapt<AppUser>();
            IdentityResult result = await userManager.CreateAsync(user, signUpViewModel.Password);
            if (result.Succeeded)
            {
             await   userManager.AddToRoleAsync(user,"User");
                return RedirectToAction("Index", "Login");
            }
            else
            {
                AddModelError(result);
            }
        }
        return View(signUpViewModel);
    }

Razor

<form asp-action="Index" method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="mb-3">
         <label class="form-label" asp-for="UserName">Kullanıcı Adı</label>
                <input asp-for="UserName" type="text" class="form-control" id="username" placeholder="Kullanıcı Adı">
          <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
    <div class="mb-3">
          <label class="form-label" asp-for="Email">Mail Adresi</label>
              <input asp-for="Email" type="text" class="form-control" id="username" placeholder="Mail Adresi">
          <span asp-validation-for="Email" class="text-danger"></span>
    </div>
        
    <div class="mb-3">
            <label class="form-label" asp-for="Password">Şifre</label>
                 <input asp-for="Password" type="password" class="form-control" id="userpassword" placeholder="Şifrenizi Oluşturun">
            <span asp-validation-for="Password" class="text-danger"></span>
    </div>
            
    <div class="mt-3 text-end">
        <button class="btn btn-primary w-sm waves-effect waves-light" type="submit">Kayıt Ol</button>
    </div>
        
      <div class="mt-4 text-center">
            <p class="text-muted mb-0">Zaten Bir Hesabınız Var Mı ? <a href="Login" class="fw-medium text-primary">Giriş Sayfası</a></p>
       </div>
    </form>

I triggered the form without typing anything in the first photo and the default Annotions returned in English

Validation is Not Working

In the second photo, I got a response as I set it. What I want is to be able to adjust the Annotations in the first photo as I want. I did this by trying the NotNull() and NotEmpty() methods in turn, but without success.

Validation is Working

If I make the properties nullable, this problem disappears, I can understand why, but what I'm wondering is how can I override the system's automatic message without making it nullable?

Upvotes: 0

Views: 244

Answers (1)

Zhi Lv
Zhi Lv

Reputation: 21546

What I want is to be able to adjust the Annotations in the first photo as I want. I did this by trying the NotNull() and NotEmpty() methods in turn, but without success.

This is a compatibility issue when using Asp.net Core build-in Validation and the FluentValidation.

After FluentValidation is executed, any other validator providers will also have a chance to execute. This means you can mix FluentValidation auto-validation with DataAnnotations attributes (or any other ASP.NET ModelValidatorProvider implementation).

And if we disable the Asp.net core DataAnnotations Validation (refer to this article:Compatibility with ASP.NET's built-in Validation), it will still meet your issue, because of the client-side validation.

So, as a workaround, I suggest you can mix FluentValidation auto-validation with DataAnnotations attributes, and set required error message twice, like this:

The DataAnnotations validation:

public class SignUpViewModel
{
    [Required(ErrorMessage = "Kullanıcı Adı Boş Bırakılamaz")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Email Boş Bırakılamaz")]
    public string Email { get; set; }
    [Required(ErrorMessage = "Şifre Boş Bırakılamaz")]
    public string Password { get; set; }

}

The FluentValidation:

public class SignUpVMValidator : AbstractValidator<SignUpViewModel>
{
    public SignUpVMValidator()
    {
        RuleFor(x => x.UserName)
            .NotNull().WithMessage("Kullanıcı Adı Boş Bırakılamaz")
            .MinimumLength(6).WithMessage("Kullanıcı Adı Minimum 6 Karakterden Oluşmalıdır")
            .MaximumLength(20).WithMessage("Kullanıcı Adı Maksimum 20 Karakterden Oluşmalıdır");

        RuleFor(x => x.Password)
            .MinimumLength(6).WithMessage("Şifre Minimum 6 Karakterden Oluşmalıdır")
            .MaximumLength(20).WithMessage("Şifre Maksimum 20 Karakterden Oluşmalıdır")
            .NotNull().WithMessage("Şifre Boş Bırakılamaz").NotEmpty().WithMessage("Şifre Boş Bırakılamaz");

        RuleFor(x => x.Email)
            .NotNull().WithMessage("Email Boş Bırakılamaz")
            .EmailAddress();
    }
}

Finally, since this issue relates the FluentValudation, you can also submit a feedback to them, might be they will provide a build-in method to solve this issue.

Upvotes: 1

Related Questions