asp.net核心:"Operations that change non-concurrent collections must have exclusive access."

asp.net core: "Operations that change non-concurrent collections must have exclusive access."

我的服务器使用 MySqlConnector 并与 AWS 上的 MySQL 数据库通信。我在 MySQL 中存储了 5 分钟的 API 计数器块。那些 API 计数器随着每个 API 调用递增,并由 ConcurrentDictionary 代码处理(这似乎不是问题)。这行代码最近引发了一个异常,它是通过 MySqlConnector 访问 MySQL 数据库 table:

的 linq 查询的一部分

await _context.ApiCounts.Where(c => c.ApiName == apiName && c.StartTime >= startTime).ToListAsync();

我以前从未见过这一行失败,但我的一台服务器突然开始在上面的行抛出以下异常:

InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
at System.ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported
at System.Collections.Generic.Dictionary`2.FindEntry
at System.Collections.Generic.Dictionary`2.TryGetValue
at Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry.GetNodeType
at Remotion.Linq.Parsing.Structure.NodeTypeProviders.MethodInfoBasedNodeTypeRegistry.IsRegistered
at System.Linq.Enumerable.Any
at Remotion.Linq.Parsing.Structure.ExpressionTreeParser.GetQueryOperatorExpression
at Remotion.Linq.Parsing.ExpressionVisitors.SubQueryFindingExpressionVisitor.Visit
at System.Linq.Expressions.ExpressionVisitor.VisitBinary
at System.Linq.Expressions.BinaryExpression.Accept
at System.Linq.Expressions.ExpressionVisitor.VisitBinary
at System.Linq.Expressions.BinaryExpression.Accept
at System.Linq.Expressions.ExpressionVisitor.VisitLambda
at System.Linq.Expressions.Expression`1.Accept
at System.Linq.Enumerable+SelectListPartitionIterator`2.ToArray
at System.Linq.Enumerable.ToArray
at Remotion.Linq.Parsing.Structure.MethodCallExpressionParser.Parse
at Remotion.Linq.Parsing.Structure.ExpressionTreeParser.ParseMethodCallExpression
at Remotion.Linq.Parsing.Structure.QueryParser.GetParsedQuery
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQueryCore
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass24_0`1.<CompileAsyncQuery>b__0
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator
at System.Linq.AsyncEnumerable+<Aggregate_>d__6`3.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
at BlayFap.Controllers.ServerController+<GetCachedApiCount>d__13.MoveNext (E:\Projects\BlayFap\BlayFap\Controllers\ServerController.cs:342)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
at BlayFap.Controllers.ServerController+<GetApiCount>d__14.MoveNext (E:\Projects\BlayFap\BlayFap\Controllers\ServerController.cs:378)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeActionMethodAsync>d__12.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeNextActionFilterAsync>d__10.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeInnerFilterAsync>d__14.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResourceFilter>d__22.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeFilterPipelineAsync>d__17.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeAsync>d__15.MoveNext
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw

所有其他 table 都可以正常访问,但是从这里开始任何使用 ApiCounts table 的尝试都会导致上述异常。我不得不重新启动受影响的服务器以清除错误。看起来这个异常与字典上的并发编辑有关,并且该字典似乎在 linq 代码中。我猜服务器可能遇到了这样一种情况,即 EF 在执行 linq 语句时同时更新和写入某种数据,然后使字典陷入一种奇怪的状态,但我不确定如何防止这种情况以及真正的问题所在。这是 .NET 错误还是我自己的错误?

更多信息:我没有在此函数中修改 ApiCounts 的结果,也没有调用 SaveChanges。但是,代码 运行 可以与此(在另一个 REST 查询中)异步更新 ApiCounts 并调用 SaveChanges。

解决方法是更新到 EF 2.1.5 或更新版本。

发生此错误时我正在使用 EF 2.0.3。看起来有一个线程不安全的单例,这可能会导致我看到的相同错误。这是 github 中的问题:https://github.com/dotnet/efcore/issues/12682

就我而言,我遇到了同样的问题。花了几个小时后,我在 IIS 中重新启动了应用程序池,它开始像一个魅力一样工作。

首先我尝试在不同的环境中重现这个问题。它仅发生在 PROD 环境中。所以我重新启动了 IIS 应用程序池,它给了我预期的输出