Reputation: 1789
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
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
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