I'm working directly with AspNetUserClaims table as it mainly belongs to my ASP.NET application but is also consumed from a Windows application. ASP.NET app does external login with Google while the Windows application periodically polls the Google account and refreshes the access token from time to time. Thus, now I'm working under that Windows app.
I'm getting an exception when trying to remove a claim from AspNetUserClaims table. It keeps telling me "The UserId field is required."
If I disable validation with dc.Configuration.ValidateOnSaveEnabled = false, I see that it tries to do UPDATE query (passing all values as NULL or defaults) instead of DELETE. It fails no matter which particular claim I'm trying to remove and even if I remove them all with Clear method.
The code also displayed all the currently available claims for all users (that's why there is foreach instead of dc.Users.Where) but I removed that parts for debugging purposes.
var dc = new IdentityDbContext();
foreach (var u in dc.Users.ToList())
{
if (u.Email == "something@gmail.com")
{
u.Claims.Clear();
}
}
dc.SaveChanges();
This only concerns removing claims. I successfully add new claims with Claims.Add or update the values of existing claims with changing Claim.ClaimValue. What could be the reason?
Actually, I can live without removing claims as my Windows app only needs to update the claim (update the access token using the refresh token). But I'm curious why deleting does not work.
Well, I found a way to remove the token with this code:
var dc = new IdentityDbContext();
var manager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(dc));
var user = manager.FindByEmail("something@gmail.com");
Claim c = manager.GetClaims(user.Id).Where(c => c.Type == "GoogleAccessToken").FirstOrDefault();
if (c != null)
{
manager.RemoveClaim(user.Id, c);
}
But it's still not clear why the original code not utilizing UserManager doesn't work on deleting claims.
These are quirks of Entity Framework.
When you say
user.Claims.Remove(claim);
dbContext.SaveChanges();
This only resets foreign key of claim object to null, but that is not allowed. EF does not know any better, hence no DELETE
statement.
If you want to delete objects in EF, do this:
dbContext.UserClaims.Remove(claim);
But you need to map IDbSet<UserClaim> UserClaims
to your dbContext
, as it is not available by default.
Read more about EF-ways of removing objects in this article