我正在使用ASP.NET Identity(v2)和Entity Framework。我正在构建一个包含多个复选框的页面,每个复选框代表一个声明。在按钮上单击(在我的示例中为SavePrivileges
函数)我想根据我的复选框的状态调整给定用户的声明,即删除未检查的声明,并添加已检查的声明。
添加声明工作正常。但是,我似乎无法删除用户的声明。在调用manager.RemoveClaim
时,我得到一个InvalidOperationException,表示集合已更改。即使我不修改user.Claims
集合,我实际上也得到了这个例外。
以下是我的简化示例场景:
protected void SavePrivileges(string userId)
{
const string claim1Type = "...";
const string claim2Type = "...";
const string claim1Value = "...";
const string claim2Value = "...";
var store = new UserStore<IdentityUser>();
var manager = new UserManager<IdentityUser>(store);
var user = manager.FindById(userId);
// Lists to keep track of changes
var removed = new List<Claim>();
var added = new List<Claim>();
bool claim1Checked = CheckBox1.Checked;
bool claim2Checked = CheckBox2.Checked;
bool claim1Possesed = user.Claims.FirstOrDefault(claim => claim.ClaimValue == claim1Value &&
claim.ClaimType == claim1Type) != null;
bool claim2Possesed = user.Claims.FirstOrDefault(claim => claim.ClaimValue == claim2Value &&
claim.ClaimType == claim2Type) != null;
if (claim1Checked && !claim1Possesed)
{
added.Add(new Claim(claim1Type, claim1Value));
}
else if (!claim1Checked && claim1Possesed)
{
removed.Add(new Claim(claim1Type, claim1Value));
}
// + The same for claim2...
// Remove extra claims
foreach (Claim claim in removed)
{
manager.RemoveClaim(user.Id, claim);
}
// Add new claims
foreach (Claim claim in added)
{
IdentityUserClaim identityUserClaim = new IdentityUserClaim { ClaimType = claim.Type, ClaimValue = claim.Value };
user.Claims.Add(identityUserClaim);
}
// Save the result
var result = manager.Update(user);
if (result.Succeeded)
{
store.Context.SaveChanges();
}
}
感谢您的帮助。
答案 0 :(得分:2)
我最终找到了一个解决方案,然而,它在任何方面都不是优雅的。如果有人想出更好的解决方案,我仍然会很高兴看到它。
foreach (Claim claim in removed) {
var claimCollection = store.Context.Entry(user).Collection(u => u.Claims).CurrentValue;
var storedClaim = claimCollection.FirstOrDefault(c => c.ClaimType == claim.Type && c.ClaimValue == claim.Value && c.UserId == user.Id);
if (storedClaim != null)
store.Context.Entry(storedClaim).State = EntityState.Deleted;
}
答案 1 :(得分:2)
这对我很有用。希望这有帮助!
user.Claims.ToList().ForEach(claim => Context.Entry(claim).State =
System.Data.Entity.EntityState.Deleted);
Context.SaveChanges();
答案 2 :(得分:0)
我已经交换到优秀的包ElCamino.AspNet.Identity.AzureTable,它提供了基于Azure表存储的实现,以替换基于标准Microsoft.AspNet.Identity.EntityFramework实体框架的身份存储。
安装了ElCamino.AspNet.Identity.AzureTable包后,正常userManager.RemoveClaimAsync
按预期工作。从这里,看看标准包中发生错误的位置,我怀疑它是Microsoft.AspNet.Identity.EntityFramework中的一个错误。