【问题标题】:MVC Action Filters Collection was modified; enumeration operation may not execute修改了 MVC 操作过滤器集合;枚举操作可能无法执行
【发布时间】:2015-04-03 09:27:43
【问题描述】:

我们在 MVC 5.1.3 应用程序中经常发生此错误,当它发生时,用户必须刷新页面并且它会消失,所以这是一个间歇性问题。

我们发现诊断起来很棘手,因为它似乎发生在框架本身内。关于在哪里看有什么想法吗?

这是完整的堆栈:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at System.Web.Mvc.FilterProviderCollection.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
   at System.Web.Mvc.ControllerActionInvoker.GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state)
   at System.Web.Mvc.Controller.<BeginExecuteCore>b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Async.AsyncResultWrapper.Begin[TState](AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext)
   at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Async.AsyncResultWrapper.Begin[TState](AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext)
   at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
   at System.Web.Mvc.Async.AsyncResultWrapper.Begin[TState](AsyncCallback callback, Object callbackState, BeginInvokeDelegate`1 beginDelegate, EndInvokeVoidDelegate`1 endDelegate, TState invokeState, Object tag, Int32 timeout, SynchronizationContext callbackSyncContext)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

之前有人问过一个类似的问题:Collection was modified; enumeration operation may not execute,但是通过升级到 MVC 5 解决了这个问题,我们已经在 5 上。

【问题讨论】:

  • 你在哪个代码上得到这个?
  • 很明显,有些东西是在运行时从全局过滤器集合中添加或删除过滤器。这应该只在启动时发生,所以你应该做的第一件事是搜索全局过滤器被修改的任何地方,并且在没有在启动时完成的任何地方都是可疑的。
  • 您是否使用过任何其他工具来更好地了解正在发生的事情?喜欢Elmahglimpse
  • 你能把你的代码也放上去吗?如果您使用自定义过滤器,请检查它们正在执行的订单。似乎在 5.1.3 中,它们正在异步执行并努力从控制器上下文中获取相同的资源。

标签: asp.net-mvc collections action-filter


【解决方案1】:

正如@Erik 在评论中所说,显然过滤器集合正在请求执行期间被修改,它应该只在应用程序启动期间填充。

一种可能是您注册了一个自定义的IFilterProvider,它正在破坏代码。这是发生错误的源代码(来自FilterProviderCollection

        for (int i = 0; i < providers.Length; i++)
        {
            IFilterProvider provider = providers[i];
            foreach (Filter filter in provider.GetFilters(controllerContext, actionDescriptor))
            {
                filters.Add(filter);
            }
        }

provider.GetFilter(...) 正在返回一个 List,稍后在枚举 FilterProviderCollectionforeach 块期间对其进行修改。

这是我想到的供你测试的内容:

  • 首先,确保您没有注册自定义 IFilterProvider(您或者您可能正在使用的库)。如果是这样,那就是主要嫌疑人。

  • 在您的代码中查找 GlobalFilterCollectionGlobalFilters 类的所有用法。对此集合的任何修改只能通过 Global.asax 中的 Application_StartStartup 类(如果您使用 OWIN)

  • 寻找您在哪里创建或访问过滤器的线索。

  • 尝试升级到 MVC 5.2。如果这是框架的问题(这似乎不太可能),这可能会解决它。 (我使用的是 5.2.2.0,在开发或生产中都没有看到任何类似的问题)

  • 调试您的应用程序,并在Application_BeginRequest 的开头和控制器操作中设置断点。尝试检查全局过滤器集合,看看是否有任何变化。

  • 也许注册一个自定义 IFilterProvider 并通过调试或日志记录检查行为可能会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 2015-06-17
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多