ASP.NET MVC + LINQexception

我有一个ASP.NET MVC应用程序,99.9%的时间都很好用。 一旦陷入蓝色的月亮,虽然事情确实出现了问题,我想知道是否有人可以对这里可能出现的问题有所了解。

Web应用程序正在使用Linq2SQL,并在以下一组指令后在控制器中爆炸:

const int pageSize = 5; var allHeadings = artRepository.FindAllVisibleHeadings(); var paginatedHeadings = new PaginatedList
(allHeadings, id ?? 0, pageSize);

allHeadings只包含文章所有可见标题的IQueryable列表,而PaginatedList负责从这个很长的列表中取出一个合适的块。 它如下:

 public PaginatedList(IQueryable source, int pageIndex, int pageSize) { PageIndex = pageIndex; PageSize = pageSize; TotalCount = source.Count(); TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize); this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize)); } 

它会在source.Count()行上爆炸,所以当它计算db中的所有可见文章时。 有趣的是,当我多次重新加载页面时,我得到两种不同的例外:

第一:序列包含多个元素

 at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult) at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) at System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression) at System.Linq.Queryable.Count[TSource](IQueryable`1 source) at KoscierzynaInfo.Helpers.PaginatedList`1..ctor(IQueryable`1 source, Int32 pageIndex, Int32 pageSize) in C:\Users\mr\Documents\Visual Studio 2008\Projects\KoscierzynaInfo\KoscierzynaInfo\Helpers\PaginatedList.cs:line 20 at KoscierzynaInfo.Controllers.HomeController.Index(Nullable`1 id) in C:\Users\mr\Documents\Visual Studio 2008\Projects\KoscierzynaInfo\KoscierzynaInfo\Controllers\HomeController.cs:line 63 at lambda_method(ExecutionScope , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.c__DisplayClassa.b__7() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) at System.Web.Mvc.ControllerActionInvoker.c__DisplayClassa.c__DisplayClassc.b__9() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) at System.Web.Mvc.Controller.ExecuteCore() at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) at System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

和第二种类型:索引超出了数组的范围

 at System.Data.SqlClient.SqlDataReader.ReadColumnHeader(Int32 i) at System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i) at Read_Article(ObjectMaterializer`1 ) at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext() at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection) at KoscierzynaInfo.Helpers.PaginatedList`1..ctor(IQueryable`1 source, Int32 pageIndex, Int32 pageSize) in C:\Users\mr\Documents\Visual Studio 2008\Projects\KoscierzynaInfo\KoscierzynaInfo\Helpers\PaginatedList.cs:line 20 at KoscierzynaInfo.Controllers.HomeController.Index(Nullable`1 id) in C:\Users\mr\Documents\Visual Studio 2008\Projects\KoscierzynaInfo\KoscierzynaInfo\Controllers\HomeController.cs:line 63 at lambda_method(ExecutionScope , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.c__DisplayClassa.b__7() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) at System.Web.Mvc.ControllerActionInvoker.c__DisplayClassa.c__DisplayClassc.b__9() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) at System.Web.Mvc.Controller.ExecuteCore() at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) at System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

我想出解决这个问题的唯一方法是重启IIS或回收池。 这个问题以前发生在你们中间吗? 它从何而来?! 那有什么补救措施吗?

我将应用程序从IIS7 + SQL Server 2005移动到另一台使用IIS6 + SQLServer 2008的服务器,希望它可以解决问题,但不幸的是它今天再次发生,这让我相信这个问题不是真正依赖于系统/数据库。

我想您可能正在使用的DataContext类与请求级别或单个级别的生命范围相关联。 如果是,我可能会建议您将范围保持在方法级别。

奇怪的LINQexception (见答案的评论)

由于您使用IQueryable作为源,这意味着仅当您在其上调用Count()时才将数据加载到source参数中。

在具有多个这样的元素的集合上调用Single()时,您可以获得第一个错误:

 var data = Enumerable.Range(1, 10).Single(); 

鉴于上述情况,我可能会说你的代码中的某个地方你调用Single()在大多数情况下 ,集合只有一个元素,但是当它有更多时,你会得到错误。

对于第二个错误:查看堆栈跟踪的顶部

SqlDataReader.ReadColumnHeader(Int32 i)

这是抛出ArgumentOutOfRangeException的方法。 这可能表示您的数据库模型未与数据库架构或查询输出同步,即您希望读取N列,而是使用NK列。

我唯一一次看到错误一是当我尝试在返回多个对象时设置单个对象时。

 if (source == null) { source = new List().AsQueryable(); } 

你试过在寻呼机中加入这样的东西吗?

看起来您也将连续两次枚举相同的源。 Count将对db运行select *并返回计数,然后Take将对数据库运行另一个查询。 你最好将结果返回到内存集合中的IEnumerable中并首先运行.Length并使用Take on the IEnumerable来获得你想要的分页结果。 如果使用Take(),SingleorDefault()或FirstorDefault(),检查长度是否为零,一个或多个可以更改

你的第二个例外不在Count()。 它出现在AddRange()中。 这很可能发生在跳过后PageSize超过剩余项目数的地方。 请注意,即使您减少了代码并进行了检查,运行AddRange时计数也可能不准确。

我猜你必须循环应用程序池的原因是因为你正在重新使用Mark已经推测的DataContext。 我建议将DataContext的重复使用减少到至少请求。 然后单个错误不会导致整个应用程序崩溃。

重要的是,即使在执行Count()时发生exception,失败的代码也不在该方法中,而是在构建IQueryable的LINQ表达式中。 这就是LINQ的奇迹, LINQ select语句仅在枚举其结果时执行

枚举(可查询的inheritance可枚举)在以下情况中列举(列表不详尽):Count,Foreach,ToList,ToArray,ToDictionary,First等。所以当我们需要一个元素或结果中的元素数量时。

更重要的是,只要存储LINQ查询的结果而不将其转换为列表或数组, 每次枚举时都会执行选择语句

话虽如此,这里有两件重要的事情:

  1. 失败的代码位于FindAllVisibleHeadings方法中,因为这是构建LINQ查询的位置。 如果没有看到代码,就很难知道确切的位置,但考虑到你得到的错误信息,你应该寻找Single或SingleOrDefault语句。

  2. 你可以多次枚举你的IQueryable(Count和Skip / Take),这有明显的代码味道。

基本的解决方案是在使用之前将IQueryable转换为列表。

 public PaginatedList(IQueryable source, int pageIndex, int pageSize) { var sourceList = source.ToList(); PageIndex = pageIndex; PageSize = pageSize; TotalCount = sourceList.Count(); TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize); this.AddRange(sourceList.Skip(PageIndex * PageSize).Take(PageSize)); } 

但单独这样做可能无法解决您的问题。 您必须认为,在FindAllVisibleHeadings方法中构建LINQ查询的那一刻与使用它的那一刻之间,您的数据可能会发生任何事情。

使FindAllVisibleHeadings返回List而不是IQueryable可能是一个好主意。 但是在我们看到其中的代码之前无法知道。