Phil
Phil

Reputation: 1789

asp.net identity SetEmailConfirmedAsync

I'm having issues with the SetEmailConfirmedAsync method within my UserStore class.

Everything is working fine, users are being created with hashed password, tokens are being generated for the confirmation email, the email is sending successfully. The problem comes when I try to verify the email

public async Task<ActionResult> ConfirmEmail(Guid userId, string token)
{
    Task<Microsoft.AspNet.Identity.IdentityResult> result = UserManager.ConfirmEmailAsync(userId, token);

    if (result.Result.Succeeded)
    {

    }
    else
    {

    }

    return View();
}

This then calls

public Task SetEmailConfirmedAsync(User user, bool confirmed) 
        {
            AccountService.VerifiyAccount(user.Id, confirmed);
            return Task.FromResult(0);
        }

which sets the account to verified as i'd expect. However, the next thing that happens is that the FindByNameAsync is called followed by the UpdateAsync method which overwirtes my changes applied within SetEmailConfirmedAsync.

Does anyone know why asp.net Identity makes a call to UpdateAsync after SetEmailConfirmedAsync? I've searched around for some clues but cant find anything.

Update

I've done some digging and pulled this from the Identity source code

public virtual async Task<IdentityResult> ConfirmEmailAsync(TKey userId, string token)
        {
            ThrowIfDisposed();
            var store = GetEmailStore();
            var user = await FindByIdAsync(userId).WithCurrentCulture();
            if (user == null)
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.UserIdNotFound,
                    userId));
            }
            if (!await VerifyUserTokenAsync(userId, "Confirmation", token).WithCurrentCulture())
            {
                return IdentityResult.Failed(Resources.InvalidToken);
            }
            await store.SetEmailConfirmedAsync(user, true).WithCurrentCulture();
            return await UpdateAsync(user).WithCurrentCulture();
        }

I'm struggling to figure out why a call to update user would be made after SetEmailConfirmedAsync has been called

Upvotes: 2

Views: 1568

Answers (2)

Phil
Phil

Reputation: 1789

Turns out I was being dumb, must remember that c# objects are reference types!

instead of this...

public Task SetEmailConfirmedAsync(User user, bool confirmed) 
{
    AccountService.VerifiyAccount(user.Id, confirmed);
    return Task.FromResult(0);
}

I just needed to do this...

public Task SetEmailConfirmedAsync(User user, bool confirmed)
{            
    user.Verified = confirmed;
    return Task.FromResult(0);
}

Set my custom confirmed field and then identity calls the updaate method which updates my user entity

public Task UpdateAsync(User user)
{
    AccountService.UpdateUser(user);
    return Task.FromResult(0);
}

Upvotes: 2

C-JARP
C-JARP

Reputation: 1088

Dunno what version of identity you are using, but the current version calls this method:

public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed)
    {
        ThrowIfDisposed();
        if (user == null)
        {
            throw new ArgumentNullException("user");
        }
        user.EmailConfirmed = confirmed;
        return Task.FromResult(0);
    }

as you can see, it only sets the user with the e-mail confirmed, but then needs to save the changes into the database, thus the

return await UpdateAsync(user).WithCurrentCulture();

Upvotes: 1

Related Questions