Closed germanftorres closed 3 years ago
Shouldn't all of these methods try to update the database as eagerly as possible?
As described in the documentation, you must call .SaveChangesAsync when you're done. The reason for this is transactions, really. Apps might need to do more than one thing -- e.g. update a Doctor and a Patient record together -- if one of them fails, we want the whole thing to rollback.
There are some caveats, as you've discovered: creating a user saves changes eagerly. The reason for that is, user email reservation is a cluster-wide operation, outside the scope of a single transaction. This is necessary for RavenDB.Identity to ensure email uniqueness when running in a cluster.
The best practice is, always call .SaveChangesAsync when you're done. As our documentation states,
In your controller actions, call .SaveChangesAsync() when you're done making changes. Typically this is done via a RavenController base class for MVC/WebAPI projects or via a page filter for Razor Pages projects.
I have a similar issue. The userManager.UpdateAsync() call fails with changes not getting persisted.
I added the RaveDb.Identity project directly to my solution and tracked the "usermanager.UpdateAsync(user)" call. In UserStore.UpdateAsync() - var changes = DbSession.Advanced.WhatChanged(); is 0 (no changes) while the user object has the updated values. Hence none of the changes are getting persisted.
dbSession.SaveChanges() is called after the UpdateAsync call. Looks like the IAsyncDocumentSession is not getting registered. Any idea why?
@ganmuru Show me your code that loads the user and updates the user.
GetUsers()
var users = await _manager.Users.ToListAsync();
AppUser has the updated IdentityUser details.
public async Task<IActionResult> Update([FromForm] AppUser model)
{
try
{
var result = await _manager.UpdateAsync(model);
if (result.Succeeded)
{
await _dbSession.SaveChangesAsync();
return NoContent();
}
return BadRequest(result);
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
I think the reason is, you're not loading an existing user and updating it; you're instead taking a user directly from the HTTP POST and updating.
To fix this, you should do something like this:
public async Task<IActionResult> Update([FromForm] AppUser model)
{
try
{
var existingUser = await _dbSession.LoadAsync(model.Id);
existingUser.UpdateFrom(model); // you implement this
var result = await _manager.UpdateAsync(existingUser);
if (result.Succeeded)
{
await _dbSession.SaveChangesAsync();
return NoContent();
}
return BadRequest(result);
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
This might be considered a bug, as I can see how it's an unexpected event here. I may update the behavior in the future to be as you expect.
Thanks for the suggestion. I ended up using https://www.nuget.org/packages/ValueInjecter/ to copy the object and it works fine.
var existingUser = await _dbSession.LoadAsync<AppUser>(model.Id);
existingUser.InjectFrom(model);
var result = await _manager.UpdateAsync(existingUser);
I also submitted a PR https://github.com/JudahGabriel/RavenDB.Identity/pull/37 for few changes related to IdentityRole and RoleStore. Can you please review and approve?
Approved, merged, and pushed out as RavenDB.Identity 8.0.5
Hi,
After configuring the RavenDB.Identity stores, I'm trying to add a user and also some claims to the user.
I see that the document representing the user get's created in the database, but the claims collection is still empty after adding the claims.
Following the code in UserStore.cs, I'm a little bit confused that only
CreateAsync
andDeleteAsync
actually persist immediatly callingravenSession.SaveChangesAsync
. I wonder if this behavior is something documented or expected by aspnet identity UserManager. Shouldn't all of these methods try to update the database as eagerly as possible?Thanks!
Germán