I have an API Controller for writing new users to a database, which looks like this:
public abstract class ApiBaseController : ApiController
{
protected UserManager<User, Guid> UserManager { get; set; }
protected dbcontext Repo { get; private set; }
public ApiBaseController()
{
UserManager = HttpContext.Current.GetOwinContext().GetUserManager<XUserManager>();
Repo = HttpContext.Current.GetOwinContext().Get<dbcontext>();
}
}
public class UsersController : ApiBaseController
{
[HttpPost]
[FeatureAuthorization(FeatureName = "Users", Permission = FeaturePermissions.Write)]
public IHttpActionResult Post([FromBody]CreateUserRequest req)
{
if (!ModelState.IsValid)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, ModelState.ToApiResponse()));
}
var user = UserManager.FindByName(req.UserName);
//some validation happens here
user = new User()
{
AuthenticationMethod = req.AuthenticationMethod,
DomainLDAP = req.DomainLDAP,
EmailAddress = req.EmailAddress,
FirstName = req.FirstName,
SecondName = req.SecondName,
MentionHandle = req.MentionHandle,
MobileNumber = req.MobileNumber,
UserName = req.UserName,
IsDeleted = false
};
IdentityResult createResult = null;
if (req.AuthenticationMethod == AuthenticationMethod.Internal)
{
createResult = UserManager.Create(user);
}
else
{
createResult = UserManager.Create(user, req.Password);
}
if (!createResult.Succeeded)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.BadRequest, new ApiResponse(createResult.Errors.ToArray())));
}
//Map user to user type
user.UserType = Repo.UserTypes.Find(req.UserTypeId);
//Map user to area
user.Area = Repo.Areas.Find(req.AreaId);
//Map user to role
var roles = new List<Role>();
roles.Add(role);
user.Roles = roles;
//Map user to retailers
user.Retailers = retailers;
UserManager.Update(user);
Repo.SaveChanges();
var dto = Mapper.Map<UserDto>(user);
return ResponseMessage(Request.CreateResponse(HttpStatusCode.Created, new ApiResponse<UserDto>(new[] { dto })));
}
}
When I debug this method and inspect the user
object at
UserManager.Update(user);
it has all of it's properties set correctly, including the GUIDs of the user type, area, role, and retailers. However, after the line executes and I check my database, the user that has been inserted has different GUIDs for those properties, and EF has inserted new lines into the user type and area tables which correspond to my new user.
If I remove the line of code which performs the update and leave the
Repo.SaveChanges();
line, the user
is inserted correctly with appropriate user type and area IDs, but the rows which should be inserted into my dbo.UserRoles and dbo.UserRetailers bridging tables are not inserted, meaning the link between the user and the role/retailers I've assigned to it are lost.
From my research on StackOverflow it seems as though the Area and User Type objects I'm fetching from the database are detached from the context, so the update creates new objects which have similar properties to the ones I fetched, but (obviously) with a different Id. However, I'm still not sure how to remedy the issue.