asp.net-mvc – Unity和Random“索引超出了数组的范围”异常
我们运行的网站有大约15.000个实时用户(谷歌分析)(大约1000个请求/秒(性能计数器)).
我们有两个Web服务器后面的负载均衡器. 有时每天有时会在一周内有一次我们的Web服务器停止执行请求并开始响应并出现错误,并且每个请求都会记录以下异常: 我们的环境:IIS 8.5,.Net 4.5.0,Mvc 5.1.0,Unity 3.5(与3.0相同),WebActivatorEx 2.0 我们无法捕捉到任何特定情况造成此错误.应用程序池回收后,一切都没有问题.在每个请求响应错误之前,没有任何与之相关的错误. 过去有一个问题与相关的旧Unity版本有关: 这里有异常细节: System.IndexOutOfRangeException Index was outside the bounds of the array. System.IndexOutOfRangeException: Index was outside the bounds of the array. at System.Collections.Generic.List`1.Enumerator.MoveNext() at System.Linq.Enumerable.WhereListIterator`1.MoveNext() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at Microsoft.Practices.Unity.NamedTypesRegistry.RegisterType(Type t,String name) at Microsoft.Practices.Unity.UnityDefaultBehaviorExtension.OnRegisterInstance(Object sender,RegisterInstanceEventArgs e) at System.EventHandler`1.Invoke(Object sender,TEventArgs e) at Microsoft.Practices.Unity.UnityContainer.RegisterInstance(Type t,String name,Object instance,LifetimeManager lifetime) at Microsoft.Practices.Unity.UnityContainerExtensions.RegisterInstance[TInterface](IUnityContainer container,TInterface instance,LifetimeManager lifetimeManager) at DemoSite.News.Portal.UI.App_Start.UnityConfig.<>c__DisplayClass1.<RegisterTypes>b__0() at DemoSite.News.Portal.Core.Controller.BaseController.Initialize(RequestContext requestContext) 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,Object state) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean& completedSynchronously) 我的配置如下: public static void RegisterTypes(IUnityContainer container) { var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); container.LoadConfiguration(section); ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container)); } 初始化方法如下: protected override void Initialize(System.Web.Routing.RequestContext requestContext) { if (requestContext.RouteData.Values["ViewActionId"] != null) { int viewActionId; if (!int.TryParse(requestContext.RouteData.Values["ViewActionId"].ToString(),out viewActionId)) return; var cacheProvider = ServiceLocator.Current.GetInstance<ICacheProvider>(); List<ViewActionClass> viewActionClasses = null; string cacheKey = CacheKeyCompute.ComputeCacheKey("ViewActionClass",CacheKeyTypes.DataCache,new KeyValuePair<string,string>("viewActionId",viewActionId.ToString())); _configuration = ServiceLocator.Current.GetInstance<IConfiguration>(); viewActionClasses = cacheProvider.AddOrGetExistingWithLock<List<ViewActionClass>>(cacheKey,() => { var viewActionClassBusiness = ServiceLocator.Current.GetInstance<IViewActionClassBusiness>(); return viewActionClassBusiness.ViewActionClassGetByViewActionId(viewActionId); }); ViewBag.ActionClass = viewActionClasses; ViewBag.Configuration = _configuration; } base.Initialize(requestContext); } 注册xml for ICacheProvider,IConfiguration和IViewActionClassBusiness <type type="DemoSite.Runtime.Caching.ICacheProvider,DemoSite.Core" mapTo="DemoSite.Runtime.Caching.ObjectCacheProvider,DemoSite.Core"> <lifetime type="containerControlledLifetimeManager" /> </type> <type type="DemoSite.Core.Configuration.IConfiguration,DemoSite.Core" mapTo="DemoSite.Core.Configuration.ConfigFileConfiguration,DemoSite.Core"> <lifetime type="containerControlledLifetimeManager" /> </type> <type type="DemoSite.News.Business.IViewActionClassBusiness,DemoSite.News.Business" mapTo="DemoSite.News.Business.Default.ViewActionClassBusiness,DemoSite.News.Business.Default"> <lifetime type="perRequestLifetimeManager" /> </type> 也许它与高流量有关. 提前致谢 解决方法
从堆栈跟踪中我可以看到,您在Web请求期间在容器中注册实例. RegisterType和RegisterInstance方法在Unity中不是线程安全的(这可能适用于.NET中的大多数DI库).这就解释了为什么这种情况发生在随机点和高负荷下.
最好只在启动时注册容器,以后不要更改容器.特别是使用依赖性倒置原则和依赖性注入模式,您可以集中处理对象图如何连接的知识,但是稍后通过执行新的注册将其再次分散.即使注册对Unity是线程安全的,你仍然很可能通过在运行时更改注册来引入竞争条件. UPDATE 您的代码具有以下导致问题的代码: ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container)); 这看起来很无辜,但实际上它会导致并发错误和内存泄漏. 因为新语句在lambda中,所以每次调用ServiceLocator.Current时都会创建一个新的UnityServiceLocator.这本身并不坏,但是UnityServiceLocator的构造函数调用container.RegisterInstance来在容器中注册自己.但正如我已经说过的那样:调用RegisterInstance`不是线程安全的. 但即使它是线程安全的,它仍然会导致应用程序中的内存泄漏,因为对RegisterInstance的调用不会替换现有的注册,而是将其附加到注册列表中.这意味着容器中的UnityServiceLocator实例列表将继续增长,并最终导致系统崩溃并出现OutOfMemoryException.你真的很幸运,你首先遇到这个并发错误,因为OOM错误将更难追溯. 修复实际上非常简单:将Un??ityServiceLocator的构造移出lambda并每次返回该单个实例: var locator = new UnityServiceLocator(container); ServiceLocator.SetLocatorProvider(() => locator); UnityServiceLocator的行为在我看来是一个设计缺陷,因为由于RegisterInstance不是线程安全的,并且UnityServiceLocator不知道它创建了多少次,所以它永远不应该从它的构造函数中调用RegisterInstance – 或者至少 – 不是没有检查是否可以安全地注册该实例. 然而问题是删除对RegisterInstance的调用是一个重大变化,但仍然可能是Unity团队的最佳解决方案.大多数用户可能不会注意到丢失的IServiceLocator注册,如果他们这样做,Unity将在这种情况下传达一个明确的异常消息.另一种选择是让UnityServiceLocator检查是否已经从容器中解析了任何实例,并且在这种情况下从UnityServiceLocator的构造函数中抛出InvalidOperationException. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – 我找不到在visual studio 2010中从工
- asp.net – 为什么我要将UnitOfWork与Repository
- asp.net-core – 使用IdentityServer 4和WS-Fede
- asp.net-mvc – 在MVC应用程序中使用ELMAH调试/跟
- C#_.NetFramework_Web项目_EXCEL数据导出
- asp.net-mvc – ASP.NET MVC 3从同一表单保存和编
- ASP.NET Forms身份验证和持久身份验证Cookie安全
- asp.net-mvc – 如何在ASP.NET控制器中获取“Mvc
- asp.net – 停止从域(也称为“无Cookie域”)设置
- 在ASP.NET应用程序中实现多语言的最佳方式