How can customize Asp.net Identity 2 username already taken validation message?
Asked Answered
W

5

26

How can i customize Asp.net Identity 2 username already taken validation message(Name XYZ is already taken.)? Thanks

Wilson answered 26/12, 2014 at 10:3 Comment(2)
I think you need to take a look at the identity model and figure out if there is any special attribute for that. Or look at the account controllerFlophouse
@qamar. In this particular case you are wrong because all the messages are embedded into Identity resourcesControversial
C
21

Well, I didn't find any simple solution to this issue. And by simple i mean modifying some message in a attribute/model/controller.

One possible solution could be:

After executing

var result = await UserManager.CreateAsync(user, model.Password);

In case that result is not successful you can check it's Errors property for the "Name XYZ is already taken." pattern and replace it with your custom message.

Another solution (this is my preferred way) is to write a custom UserValidation class:

 /// <summary>
    ///     Validates users before they are saved to an IUserStore
    /// </summary>
    /// <typeparam name="TUser"></typeparam>
    public class CustomUserValidator<TUser> : UserValidator<TUser, string>
        where TUser : ApplicationUser
    {
        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="manager"></param>
        public CustomUserValidator(UserManager<TUser, string> manager) : base(manager)
        {
            this.Manager = manager;
        }

        private UserManager<TUser, string> Manager { get; set; }

        /// <summary>
        ///     Validates a user before saving
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public override async Task<IdentityResult> ValidateAsync(TUser item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            var errors = new List<string>();
            await ValidateUserName(item, errors);
            if (RequireUniqueEmail)
            {
                await ValidateEmail(item, errors);
            }
            if (errors.Count > 0)
            {
                return IdentityResult.Failed(errors.ToArray());
            }
            return IdentityResult.Success;
        }

        private async Task ValidateUserName(TUser user, List<string> errors)
        {
            if (string.IsNullOrWhiteSpace(user.UserName))
            {
                errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Name"));
            }
            else if (AllowOnlyAlphanumericUserNames && !Regex.IsMatch(user.UserName, @"^[A-Za-z0-9@_\.]+$"))
            {
                // If any characters are not letters or digits, its an illegal user name
                errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidUserName, user.UserName));
            }
            else
            {
                var owner = await Manager.FindByNameAsync(user.UserName);
                if (owner != null && !EqualityComparer<string>.Default.Equals(owner.Id, user.Id))
                {
                    errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateName, user.UserName));
                }
            }
        }

        // make sure email is not empty, valid, and unique
        private async Task ValidateEmail(TUser user, List<string> errors)
        {
            if (!user.Email.IsNullOrWhiteSpace())
            {
                if (string.IsNullOrWhiteSpace(user.Email))
                {
                    errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.PropertyTooShort, "Email"));
                return;
                }
                try
                {
                    var m = new MailAddress(user.Email);
                }
                catch (FormatException)
                {
                    errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.InvalidEmail, email));
                return;
                }
            }
            var owner = await Manager.FindByEmailAsync(user.Email);
            if (owner != null && !EqualityComparer<string>.Default.Equals(owner.Id, user.Id))
            {
                errors.Add(String.Format(CultureInfo.CurrentCulture, Resources.DuplicateEmail, email));
            }
        }
    }

You can see that for all the validation error messages Resources being used, So by specifying a custom format in your resources you will be able to customize those messages.

You can register your validator in ApplicationUserManager class, Create method:

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
{
   manager.UserValidator = new CustomUserValidator<ApplicationUser>(manager)
   {
       AllowOnlyAlphanumericUserNames = false,
       RequireUniqueEmail = true
   };
}
Controversial answered 26/12, 2014 at 13:10 Comment(5)
It is unbelievable that you are required to implement your own validator in order to change a string.Palaeozoic
And I don't even see how you can replace the error message without creating a new IdentityResult since Errors is a read-only IEnumerable.Gawain
When trying this I get the error 'Resources' is inaccessible due to its protection level. If I check the class Microsoft.AspNet.Identity.Resources it is marked as internal.Loam
Solved 'Resources' is inaccessible due to its protection level here: #39123539Loam
Your answer( stackoverflow.com/questions/39123039/…) is basically the same. You probably missed those lines: Another solution (this is my preferred way) is to write a custom UserValidation class... You can see that for all the validation error messages Resources being used, So by specifying a custom format in your resources you will be able to customize those messages.Controversial
S
20

It can be done much easier than the accepted answer.

Add a class and inherit it from IdentityErrorDescriber

public class AppErrorDescriber : IdentityErrorDescriber
    {
        public override IdentityError DuplicateUserName(string userName)
        {
            var error = base.DuplicateUserName(userName);
            error.Description = "This email address has already been registered. Please log in.";
            return error;
        }
    }

Now use the new class in your Startup.cs and that's it.

services.AddDefaultIdentity<AppUser>(options => ... )
                .AddErrorDescriber<AppErrorDescriber>();
Sext answered 20/5, 2020 at 16:4 Comment(2)
Great solution!! PS if you have scaffolded the pages, service should be added in IdentityHostingStartup.csMenander
Best answer by farMirza
H
2

Just customize your AddErrors method like this:

private void AddErrors(IdentityResult result)
{
    foreach (var error in result.Errors)
    {
        if (error.StartsWith("Name"))
        {
            var NameToEmail= Regex.Replace(error,"Name","Email");
            ModelState.AddModelError("", NameToEmail);
        }
        else
        {
            ModelState.AddModelError("", error);
        }
    }
}
Holbein answered 19/9, 2017 at 7:6 Comment(0)
K
0

Use XLocalizer - Nuget package for localization. See docs here.

Kempe answered 22/12, 2020 at 8:5 Comment(0)
C
-1

The easy way to add your own property to ApplicationUser class like:

 public class AppUser:IdentityUser
  {
     public string MyUserName{get; set;}
  }
Crocked answered 12/10, 2016 at 9:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.