Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of error cases in use _userManager.CreateAsync(user, password)

UserManager.CreateAsync Method (TUser, String) doesn't mention about errors.

In controller, I jsut edit something like:

public async Task<ObjectResult> Register(RegisterViewModel model, string returnUrl = null)
{
    IDictionary<string, object> value = new Dictionary<string, object>();
    value["Success"] = false;
    value["ReturnUrl"] = returnUrl;

    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { Id = Guid.NewGuid().ToString(), UserName = model.Email, Email = model.Email };

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

        if (result.Succeeded)
        {
            await _signInManager.SignInAsync(user, isPersistent: false);
            value["Success"] = true;
        }
        else
        {
            value["ErrorMessage"] = result.Errors;
        }    
    }

    return new ObjectResult(value);
}

In client:

$scope.registerForm_submit = function ($event, account) {
    $event.preventDefault();

    if (registerForm.isValid(account)) {

        // registerForm.collectData returns new FormData() which contains
        // email, password, confirmpassword, agreement, returnurl...

        let formData = registerForm.collectData(account),                
            xhttp = new XMLHttpRequest();

        xhttp.onreadystatechange = function () {
            if (xhttp.readyState === XMLHttpRequest.DONE) {
                let data = JSON.parse(xhttp.responseText);

                if (data['Success']) {
                    window.location = '/'
                } else {                        
                    if (data['ErrorMessage'][0]['code'] === 'DuplicateUserName') {
                        let li = angular.element('<li/>').text(`Email ${account['email']} already exists.`);
                        angular.element('div[data-valmsg-summary=true] ul').html(li);
                    }
                }
            }
        }

        xhttp.open('POST', '/account/register');
        xhttp.send(formData);
    }
};

I've tried to register new account with an existing email and got the code:

data['ErrorMessage'][0]['code'] === 'DuplicateUserName'

My question: how to check other cases?

like image 385
Tân Avatar asked Nov 14 '16 07:11

Tân


2 Answers

The error codes defined in ASP.NET Identity are found at https://aspnetidentity.codeplex.com/SourceControl/latest#src/Microsoft.AspNet.Identity.Core/Resources.Designer.cs - I've extracted them out to this list:

  • DefaultError
  • DuplicateEmail
  • DuplicateName
  • ExternalLoginExists
  • InvalidEmail
  • InvalidToken
  • InvalidUserName
  • LockoutNotEnabled
  • NoTokenProvider
  • NoTwoFactorProvider
  • PasswordMismatch
  • PasswordRequireDigit
  • PasswordRequireLower
  • PasswordRequireNonLetterOrDigit
  • PasswordRequireUpper
  • PasswordTooShort
  • PropertyTooShort
  • RoleNotFound
  • StoreNotIQueryableRoleStore
  • StoreNotIQueryableUserStore
  • StoreNotIUserClaimStore
  • StoreNotIUserConfirmationStore
  • StoreNotIUserEmailStore
  • StoreNotIUserLockoutStore
  • StoreNotIUserLoginStore
  • StoreNotIUserPasswordStore
  • StoreNotIUserPhoneNumberStore
  • StoreNotIUserRoleStore
  • StoreNotIUserSecurityStampStore
  • StoreNotIUserTwoFactorStore
  • UserAlreadyHasPassword
  • UserAlreadyInRole
  • UserIdNotFound
  • UserNameNotFound
  • UserNotInRole

ASP.NET Core Identity has these codes defined:

  • DefaultError
  • ConcurrencyFailure
  • PasswordMismatch
  • InvalidToken
  • LoginAlreadyAssociated
  • InvalidUserName
  • InvalidEmail
  • DuplicateUserName
  • DuplicateEmail
  • InvalidRoleName
  • DuplicateRoleName
  • UserAlreadyHasPassword
  • UserLockoutNotEnabled
  • UserAlreadyInRole
  • UserNotInRole
  • PasswordTooShort
  • PasswordRequiresNonAlphanumeric
  • PasswordRequiresDigit
  • PasswordRequiresLower
  • PasswordRequiresUpper

So, it's possible that not all of the former error codes will actually show up in an IdentityResult. I don't use either, so this is just what I gather from skimming the available source code. Caveat emptor...

Seems like this should be documented somewhere...

I like to have strings of this nature defined in one place, so I typically do something like:

public class IdentityErrorCodes
{
    public const string DefaultError                    = "DefaultError";
    public const string ConcurrencyFailure              = "ConcurrencyFailure";
    public const string PasswordMismatch                = "PasswordMismatch";
    public const string InvalidToken                    = "InvalidToken";
    public const string LoginAlreadyAssociated          = "LoginAlreadyAssociated";
    public const string InvalidUserName                 = "InvalidUserName";
    public const string InvalidEmail                    = "InvalidEmail";
    public const string DuplicateUserName               = "DuplicateUserName";
    public const string DuplicateEmail                  = "DuplicateEmail";
    public const string InvalidRoleName                 = "InvalidRoleName";
    public const string DuplicateRoleName               = "DuplicateRoleName";
    public const string UserAlreadyHasPassword          = "UserAlreadyHasPassword";
    public const string UserLockoutNotEnabled           = "UserLockoutNotEnabled";
    public const string UserAlreadyInRole               = "UserAlreadyInRole";
    public const string UserNotInRole                   = "UserNotInRole";
    public const string PasswordTooShort                = "PasswordTooShort";
    public const string PasswordRequiresNonAlphanumeric = "PasswordRequiresNonAlphanumeric";
    public const string PasswordRequiresDigit           = "PasswordRequiresDigit";
    public const string PasswordRequiresLower           = "PasswordRequiresLower";
    public const string PasswordRequiresUpper           = "PasswordRequiresUpper";

    public static string[] All = { 
        DefaultError,
        ConcurrencyFailure,
        PasswordMismatch,
        InvalidToken,
        LoginAlreadyAssociated,
        InvalidUserName,
        InvalidEmail,
        DuplicateUserName,
        DuplicateEmail,
        InvalidRoleName,
        DuplicateRoleName,
        UserAlreadyHasPassword,
        UserLockoutNotEnabled,
        UserAlreadyInRole,
        UserNotInRole,
        PasswordTooShort,
        PasswordRequiresNonAlphanumeric,
        PasswordRequiresDigit,
        PasswordRequiresLower,
        PasswordRequiresUpper 
    };
}

This lets you be consistent in the keys you're using as lookups, and the last field, All, gives you an array you can enumerate through, if necessary.

Using your code, you can do this:

if(data['ErrorMessage'][0]['code'] == IdentityErrorCodes.DuplicateUserName)
{
}

And so on.

like image 113
Tieson T. Avatar answered Nov 10 '22 19:11

Tieson T.


For ASP.NET Core you can find the different error types in the IdentityErrorDescriber class under the namespace Microsoft.AspNetCore.Identity.

As you can see, the error codes are generated via nameof(), e.g:

Code = nameof(DuplicateUserName)

So you could also use that for your cases:

data['ErrorMessage'][0]['code'] == nameof(IdentityErrorDescriber.DuplicateUserName)

This way you don't have to curate a list of error codes as suggested in another answer to your question.

like image 12
B12Toaster Avatar answered Nov 10 '22 18:11

B12Toaster