Batch UserManager.CreateAsync & UserManager.AddToRoleAsync

Nov 26, 2014 at 1:19 PM
Edited Nov 27, 2014 at 11:04 PM
Hi

I'm new to this (c# and azure) so please excuse me if I'm asking silly questions. I'm building my user service as a WebApi project and want to use AzureTables.

As part of the User Service i have two groups of users that can register. So i have two registration end points /api/account/register/user & /api/account/register/provider.

When I process these requests in my AccountController i make a call to UserManager.CreateAsync (this was the default I've seen in all ASP.net Identity samples).

Now I could add code (see sample code below) to the method in the account controller register method that adds a role for a user using the UserManager.AddToRoleAsync but these calls happen independent of each other and doesn't complete atomically. i.e. the user could be added to the role with could fail. Correct?

in my AccountController Class i've done this.

        [AllowAnonymous]
        [Route("Register/User")]
        public async Task<IHttpActionResult> Register(RegisterBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            
            var result = await UserManager.CreateAsync(user, model.Password);

            if (!result.Succeeded) return GetErrorResult(result);
            result = await UserManager.AddToRoleAsync(user.Id, "USER");

            return !result.Succeeded ? GetErrorResult(result) : Ok();
        }

My problem is I could end up with orphaned records if the second write fails. e.g. user with no role. I'm trying to avoid this.

I took a look at the implementation of public async virtual Task CreateAsync(TUser user) in the Elcamino UserStore and noticed that it does batched writes. As far as i can see the code is just Waiting for all the operations in the batch to complete. I understand from the documentation that Entity Group Transactions are processed atomically so this is exactly what i need for the User and the UserRole writes that i want to make.

So now to my questions:
  1. I can't seem to find a method that writes the IdentityUser and IdentityUserRole to the AspNetUsers table atomically. Is there a method that I've missed ?
  2. I could just extend the UserStore class in my code and create my own method that batches these writes, is this the correct way to go?
  3. Is there something fundamental that I've missed and I should be looking at a different direction?
BTW: Thanks for this library it is awesome and has save me loads of time if i tried to learn Azure and AspNet.Identity so that i could extend AspNet.Identity to persist data in Azure. Awesome job!
Nov 28, 2014 at 2:09 AM
Edited Nov 28, 2014 at 2:10 AM
No worries. I solved this in the following way.
  1. I can't extend the UserStore and create a batched method to create the User and Role as I need to be able to get access to a method similar to UserManager.CreateAsync(user, model.Password); so I can see how the library does the password hashing. It seems like the User Store in this library only overrides the CreateAsync(TUser user);
  2. In my controller I use the DeleteAsync method (with retry) to delete the user if I get a situation where the user was created and the role creation failed. For now this seems to have solved my problem.
Marked as answer by nish66d on 11/27/2014 at 7:09 PM