Search code examples
c#asp.net-coreasp.net-core-2.0asp.net-core-identity

.net core Identity, getting specific signup error conditions


I wish to test/deal with specific error conditions returned from UserManager, eg: registration failed due to username already on file, etc

var user = new SiteUser() { UserName = username, Email = RegisterViewModel.Email };
var result = await _userManager.CreateAsync(user, RegisterViewModel.Password);
if (!result.Succeeded)
{
    // here I want to test for specific error conditions
    // eg: username already on file, etc
    // how can I do this?
}

Solution

  • IdentityResult contains an Errors property, which is of type IEnumerable<IdentityError>. IdentityError itself contains both a Code property and a Description property. This means that your result variable in your OP has an Errors property that describes the specific errors that occurred.

    IdentityErrorDescriber is used for generating instances of IdentityError. Here's an example from the source:

    public virtual IdentityError DuplicateUserName(string userName)
    {
        return new IdentityError
        {
            Code = nameof(DuplicateUserName),
            Description = Resources.FormatDuplicateUserName(userName)
        };
    }
    

    IdentityErrorDescriber is injected into the DI system in the same way that UserManager is. This means you can take it as a dependency in your controller's construtor (for example) and use it later, like so (assuming _errorDescriber has been created and set in your constructor):

    if (!result.Succeeded)
    {
        // DuplicateUserName(...) requires the UserName itself so it can add it in the
        // Description. We don't care about that so just provide null.
        var duplicateUserNameCode = _errorDescriber.DuplicateUserName(null).Code;
    
        // Here's another option that's less flexible but removes the need for _errorDescriber.
        // var duplicateUserNameCode = nameof(IdentityErrorDescriber.DuplicateUserName); 
    
        if (result.Errors.Any(x => x.Code == duplicateUserNameCode))
        {
            // Your code for handling DuplicateUserName.
        }
    }
    

    There are a number of different ways to get the Code value you want to test against and to do the check itself - this is just one example that's fairly safe against customisations you might want to make to the codes and errors themselves.

    If you're interested, here's a link to the source for where the DuplicateUserName error is added to the IdentityResult you get back.

    I've only talked about DuplicateUserName here, but there are other IdentityErrorDescriber values for e.g. InvalidEmail that you might also want to check for.