asp.net-core - 如何处理 IdentityUser 更新并发失败?

标签 asp.net-core asp.net-identity claims-based-identity asp.net-core-1.0 claims

我有一种方法可以在我们的应用程序中更新用户声明。

我以管理员用户身份登录,可以编辑其他用户。

我正在尝试删除一位用户的现有声明并分配新的声明。

使用 UserManger 删除声明时我收到 ConcurrencyFailure其结果。 (有时它可以工作,但大多数时候它会返回失败错误。)

Code: "ConcurrencyFailure"

Description: "Optimistic concurrency failure, object has been modified."



方法:
    public async Task<bool> AssignClaimsToUser(string id, List<string> newClaims)
    {
        bool success = false;

        ApplicationUser user = await _userManager.FindByIdAsync(id);
        List<Claim> userClaims = new List<Claim>();

        // Remove existing claims
        IList<Claim> existingClaims = await _userManager.GetClaimsAsync(user);
        var removal = await _userManager.RemoveClaimsAsync(user, existingClaims); // This fail

        if (removal.Succeeded)
        {
            success = true;

            // Add new claims
            foreach (string policy in newClaims)
            {
                userClaims.Add(new Claim(policy, string.Empty, ClaimValueTypes.String));
            }
            await _userManager.AddClaimsAsync(user, userClaims);
        }

        return success;
    }

为什么会发生这种情况以及如何解决此问题?

我只有在删除声明时才会遇到这个问题。我在 IdentityUser 上调用其他方法时没有它.

编辑

调试输出:

enter image description here

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:47691/Users/ManageUsers_Update application/x-www-form-urlencoded; charset=UTF-8 246 Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Identity.Application. Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful for user: user@mydomain.com. Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization was successful for user: user@mydomain.com. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method MyProject.Controllers.UsersController.ManageUsers_Update (MyProject) with arguments (Kendo.Mvc.UI.DataSourceRequest, MyProject.Views.ViewModels.ManageUsersViewModel) - ModelState is Valid Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__custRef_0='?' (Size = 10)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [c].[CustomerDetailsId], [c].[CustRef], [c].[CustomerDBConnectionString], [c].[Enabled], [c].[Name], [c].[UserLicenses] FROM [CustomerDetails] AS [c] WHERE [c].[CustRef] = @__custRef_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__custRef_0='?' (Size = 10)], CommandType='Text', CommandTimeout='30'] SELECT [x].[ID], [x].[AspNetUserId], [x].[CustRef], [x].[CustomerId], [x].[Email], [x].[FirstName], [x].[IsEnabled], [x].[IsMaster], [x].[ShowCosts], [x].[Surname] FROM [Users] AS [x] WHERE [x].[CustRef] = @__custRef_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__users_Id_0='?'], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [a].[ID], [a].[AspNetUserId], [a].[CustRef], [a].[CustomerId], [a].[Email], [a].[FirstName], [a].[IsEnabled], [a].[IsMaster], [a].[ShowCosts], [a].[Surname] FROM [Users] AS [a] WHERE [a].[ID] = @__users_Id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[NormalizedUserName] = @__normalizedUserName_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (6ms) [Parameters=[@p16='?' (Size = 450), @p0='?', @p1='?' (Size = 4000), @p17='?' (Size = 4000), @p2='?' (Size = 4000), @p3='?' (Size = 256), @p4='?', @p5='?', @p6='?', @p7='?', @p8='?' (Size = 256), @p9='?' (Size = 256), @p10='?' (Size = 4000), @p11='?' (Size = 4000), @p12='?', @p13='?' (Size = 4000), @p14='?', @p15='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; UPDATE [AspNetUsers] SET [AccessFailedCount] = @p0, [ConcurrencyStamp] = @p1, [CustRef] = @p2, [Email] = @p3, [EmailConfirmed] = @p4, [IsEnabled] = @p5, [LockoutEnabled] = @p6, [LockoutEnd] = @p7, [NormalizedEmail] = @p8, [NormalizedUserName] = @p9, [PasswordHash] = @p10, [PhoneNumber] = @p11, [PhoneNumberConfirmed] = @p12, [SecurityStamp] = @p13, [TwoFactorEnabled] = @p14, [UserName] = @p15 WHERE [Id] = @p16 AND [ConcurrencyStamp] = @p17; SELECT @@ROWCOUNT; Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__menuId_0='?'], CommandType='Text', CommandTimeout='30'] SELECT [u].[CustomerMenuId], [u].[MenuItemId] FROM [CustomerMenuItem] AS [u] WHERE [u].[CustomerMenuId] = @__menuId_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT [m].[Id], [m].[AspNetPolicyId], [m].[GlyphIcon], [m].[Label], [m].[MenuGroupId] FROM [MenuItem] AS [m] Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30'] SELECT [a].[Id], [a].[DefaultAction], [a].[Description], [a].[Name] FROM [AspNetPolicy] AS [a] Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[Id] = @__id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__user_Id_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE [uc].[UserId] = @__user_Id_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (9ms) [Parameters=[@__8__locals1_user_Id_0='?' (Size = 450), @__claim_Value_1='?' (Size = 4000), @__claim_Type_2='?' (Size = 4000)], CommandType='Text', CommandTimeout='30'] SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (6ms) [Parameters=[@__8__locals1_user_Id_0='?' (Size = 450), @__claim_Value_1='?' (Size = 4000), @__claim_Type_2='?' (Size = 4000)], CommandType='Text', CommandTimeout='30'] SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (93ms) [Parameters=[@__8__locals1_user_Id_0='?' (Size = 450), @__claim_Value_1='?' (Size = 4000), @__claim_Type_2='?' (Size = 4000)], CommandType='Text', CommandTimeout='30'] SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId] FROM [AspNetUserClaims] AS [uc] WHERE (([uc].[UserId] = @__8__locals1_user_Id_0) AND ([uc].[ClaimValue] = @__claim_Value_1)) AND ([uc].[ClaimType] = @__claim_Type_2) Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (5ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[CustRef], [u].[Email], [u].[EmailConfirmed], [u].[IsEnabled], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName] FROM [AspNetUsers] AS [u] WHERE [u].[NormalizedUserName] = @__normalizedUserName_0 Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (6ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p19='?' (Size = 450), @p3='?', @p4='?' (Size = 4000), @p20='?' (Size = 4000), @p5='?' (Size = 4000), @p6='?' (Size = 256), @p7='?', @p8='?', @p9='?', @p10='?', @p11='?' (Size = 256), @p12='?' (Size = 256), @p13='?' (Size = 4000), @p14='?' (Size = 4000), @p15='?', @p16='?' (Size = 4000), @p17='?', @p18='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p0; SELECT @@ROWCOUNT; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p1; SELECT @@ROWCOUNT; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p2; SELECT @@ROWCOUNT; UPDATE [AspNetUsers] SET [AccessFailedCount] = @p3, [ConcurrencyStamp] = @p4, [CustRef] = @p5, [Email] = @p6, [EmailConfirmed] = @p7, [IsEnabled] = @p8, [LockoutEnabled] = @p9, [LockoutEnd] = @p10, [NormalizedEmail] = @p11, [NormalizedUserName] = @p12, [PasswordHash] = @p13, [PhoneNumber] = @p14, [PhoneNumberConfirmed] = @p15, [SecurityStamp] = @p16, [TwoFactorEnabled] = @p17, [UserName] = @p18 WHERE [Id] = @p19 AND [ConcurrencyStamp] = @p20; SELECT @@ROWCOUNT; 'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Users\jsmith.nuget\packages\system.diagnostics.stacktrace\4.3.0\lib\netstandard1.3\System.Diagnostics.StackTrace.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. Microsoft.EntityFrameworkCore.DbContext:Error: An exception occurred in the database while saving changes. Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions. at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__47.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__45.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.DbContext.d__30.MoveNext()

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions. at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__47.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__45.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.EntityFrameworkCore.DbContext.d__30.MoveNext() Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommandBuilderFactory:Information: Executed DbCommand (6ms) [Parameters=[@p0='?', @p1='?', @p2='?', @p19='?' (Size = 450), @p3='?', @p4='?' (Size = 4000), @p20='?' (Size = 4000), @p5='?' (Size = 4000), @p6='?' (Size = 256), @p7='?', @p8='?', @p9='?', @p10='?', @p11='?' (Size = 256), @p12='?' (Size = 256), @p13='?' (Size = 4000), @p14='?' (Size = 4000), @p15='?', @p16='?' (Size = 4000), @p17='?', @p18='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SET NOCOUNT ON; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p0; SELECT @@ROWCOUNT; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p1; SELECT @@ROWCOUNT; DELETE FROM [AspNetUserClaims] WHERE [Id] = @p2; SELECT @@ROWCOUNT; UPDATE [AspNetUsers] SET [AccessFailedCount] = @p3, [ConcurrencyStamp] = @p4, [CustRef] = @p5, [Email] = @p6, [EmailConfirmed] = @p7, [IsEnabled] = @p8, [LockoutEnabled] = @p9, [LockoutEnd] = @p10, [NormalizedEmail] = @p11, [NormalizedUserName] = @p12, [PasswordHash] = @p13, [PhoneNumber] = @p14, [PhoneNumberConfirmed] = @p15, [SecurityStamp] = @p16, [TwoFactorEnabled] = @p17, [UserName] = @p18 WHERE [Id] = @p19 AND [ConcurrencyStamp] = @p20; SELECT @@ROWCOUNT; Microsoft.EntityFrameworkCore.DbContext:Error: An exception occurred in the database while saving changes. Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions. at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagation(Int32 commandIndex, DbDataReader reader) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(DbDataReader reader) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList1 entriesToSave) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess) at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions. at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagation(Int32 commandIndex, DbDataReader reader) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(DbDataReader reader) at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection) at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable1 commandBatches, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList1 entriesToSave) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess) at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess) Exception thrown: 'Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException' in Microsoft.EntityFrameworkCore.dll The thread 0x6264 has exited with code 0 (0x0). The thread 0xaa0 has exited with code 0 (0x0). The thread 0x6a84 has exited with code 0 (0x0).



管理用户_更新:
    public async  Task<ActionResult> ManageUsers_Update([DataSourceRequest] DataSourceRequest request, ManageUsersViewModel viewModel)
    {
        if (viewModel != null && ModelState.IsValid)
        {
            User objToUpdate = new User
            {
                Id = viewModel.ID,
                FirstName = viewModel.FirstName,
                Surname = viewModel.Surname
            };
            _userRepository.UpdateUser(objToUpdate);

            if (viewModel.CustomerMenuId != null && viewModel.CustomerMenuId > 0)
            {
                int customerMenuId = Convert.ToInt32(viewModel.CustomerMenuId);

                // Update user's claims
                List<string> newClaims = _navigationRepository.GetPolicyNamesByCustomerMenuId(customerMenuId);
                bool claimsUpdated = await _applicationUserService.AssignClaimsToUser(viewModel.AspNetUserId, newClaims);

                // Assign user to menu if updating claims succeeded
                if (claimsUpdated)
                {
                    _navigationRepository.AssignCustomerMenuToUser(new CustomerMenuUser()
                        {CustomerMenuId = customerMenuId, AspNetUserId = viewModel.AspNetUserId});
                }
            }

            ApplicationUser user = await _userManager.FindByIdAsync(viewModel.AspNetUserId);
            user.IsEnabled = viewModel.IsEnabled;
            await _userManager.UpdateAsync(user);
        }

        return Json(new[] { viewModel }.ToDataSourceResult(request, ModelState));
    }

最佳答案

为什么会发生?

最可能的原因是并发冲突,这意味着多个用户(线程)尝试更改相同的数据。

在这里您可以找到有关它如何发生的更多详细信息

https://docs.microsoft.com/en-us/ef/core/saving/concurrency

怎么做才能解决这个问题?

我假设在您的情况下,多个用户不应该更新相同的声明,因此可能存在请求重复。

你可以试试:

  • 检查数据库中的数据是否更新。在多个请求的情况下,其中一个应该保存更改;
  • 在发布请求时检查浏览器中的网络选项卡或设置一个断点并查看在单个请求中它被击中的次数;
  • 从应用程序中隔离有缺陷的代码并尝试重现该问题。

  • 另一种方法(通常在允许多次访问时)是实现重试策略以在乐观失败的情况下重新执行更新逻辑。
    我很确定这不适合您的情况,但是如果您需要快速解决方案,这将起作用。

    关于asp.net-core - 如何处理 IdentityUser 更新并发失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52553964/

    相关文章:

    c# - 单元测试保存更改失败

    c# - 如何将方法参数传递给方法的属性值?

    c# - 转换 ASP.Net Core 中的 Open Id Connect 声明

    asp.net-core - 如何正确验证 API 中的 OpenIddict JWT access_token?

    typescript - 将 typescript 定义文件编译到 wwwroot 文件夹时出现“重复标识符”错误

    c# - 如何使用组织身份验证从 Blazor Server 中的身份获取用户属性

    c# - 配置授权服务器端点

    wcf - 为什么使用基于声明的身份验证需要资源/操作而不是类型/值

    visual-studio - 尝试从 Docker 中的 VS 运行时出现错误 "getcwd() failed: No such file or directory"

    c# - AspNet.Identity CreateAsync 不返回 user.Id 与 CustomStore