Closed pahlgrimm closed 4 years ago
Hi, I have customized the UpdateAsync method and it seems to work (with updating the Compare Exchange values).
Here's my code if you want to add it or if you find error to improve it:
` public async Task
// Make sure we have a valid user name.
if (string.IsNullOrWhiteSpace(user.UserName))
{
throw new ArgumentException("The user's user name can't be null or empty.", nameof(user));
}
cancellationToken.ThrowIfCancellationRequested();
// Clear session because oldUSer would not be loaded from database because it has the same id as user
DbSession.Advanced.Clear();
// We must delete the old ExchangeCompareKey if the user name hast changed
// Therefore we get the unchanged user from database and compare the old username with the current username
var oldUser = await DbSession.LoadAsync<TUser>(user.Id,cancellationToken);
if (user.UserName != oldUser.UserName)
{
// See if the user name is already taken.
// We do this using Raven's compare/exchange functionality, which works cluster-wide.
// https://ravendb.net/docs/article-page/4.1/csharp/client-api/operations/compare-exchange/overview#creating-a-key
//
// Try to reserve a new user name
// Note: This operation takes place outside of the session transaction it is a cluster-wide reservation.
var compareExchangeKey = GetCompareExchangeKeyFromUserName(user.UserName);
var reserveUserNameOperation = new PutCompareExchangeValueOperation<string>(compareExchangeKey, user.Id, 0);
var reserveUserNameResult = await DbSession.Advanced.DocumentStore.Operations.SendAsync(reserveUserNameOperation);
if (!reserveUserNameResult.Successful)
{
return IdentityResult.Failed(new[]
{
new IdentityError
{
Code = "DuplicateUserName",
Description = $"The user name {user.UserName} is already taken."
}
});
}
// Remove the cluster-wide compare/exchange key.
var deletionResult = await DeleteUserNameReservation(oldUser.UserName);
if (!deletionResult.Successful)
{
return IdentityResult.Failed(new[]
{
new IdentityError
{
Code = "ConcurrencyFailure",
Description = "Unable to delete user name compare/exchange value"
}
});
}
}
// Clear session because we won't be able to store user (same id => exception!)
DbSession.Advanced.Clear();
// This model allows us to lookup a user by name in order to get the id
await DbSession.StoreAsync(user, cancellationToken);
// Because this a a cluster-wide operation due to compare/exchange tokens,
// we need to save changes here; if we can't store the user,
// we need to roll back the email reservation.
try
{
await DbSession.SaveChangesAsync();
}
catch (Exception)
{
// The compare/exchange email reservation is cluster-wide, outside of the session scope.
// We need to manually roll it back.
await this.DeleteUserEmailReservation(user.Email);
throw;
}
return IdentityResult.Success;
}
`
I have also customized that the field UserName is used instead of Email.
Thanks for the error report. I'll have a look.
Fixed. The fix is available in RavenDB.Identity 6.2.0.2.
Thanks!
Hi I am using your library and CreateAsync works like a charm, but UpdateAsync does just nothing.