Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've got a ASP.NET MVC application that works great for 99.9% of the time. Once in a blue moon though things go really wrong and I was wondering if anybody could shed some light on what might go wrong here.

The web application is using Linq2SQL and blows up in a controller after the following set of instructions:

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

allHeadings contains just an IQueryable list of all visible headings for articles, whereas PaginatedList takes care of taking an appropriate chunk out of this very long list. It's as follows:

public PaginatedList(IQueryable<T> 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));
}

It blows up on the source.Count() line so when it's counting all the visible articles in the db. Funny thing though is that when I reload the page multiple times I'm getting 2 different kinds of exceptions:

THE FIRST: Sequence contains more than one element

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.<InvokeActionMethodWithFilters>b__7()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<>c__DisplayClassc.<InvokeActionMethodWithFilters>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)

AND THE SECOND TYPE: Index was outside of the bounds of the array

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.<InvokeActionMethodWithFilters>b__7()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<>c__DisplayClassc.<InvokeActionMethodWithFilters>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)

The only way I came up with to fix this problem was restarting IIS or recycling the pool. Did this issue happen to any of you before? Where does it come from?! And is there any remedy for that?

I moved the application from IIS7 + SQL Server 2005 to another server with IIS6 + SQLServer 2008 hoping that it would solve the problem, but unfortunately it happened again today, which leads me to believe that this issue is not really system/db dependent.

share|improve this question
    
The Count method itself seems pretty harmless, but if a bunch of objects are being loaded from the database with that method call, these kind of exceptions can occur. I'm guessing "allHeadings" is a complex object and the loading of that object is doing unsafe things like making bad assumptions about row counts being returned in various scenarios. Without more info, it's difficult to speculate further. Your best bet is to get the query to execute before PaginatedList is called so the error occurs closer to the source of the problem. Good luck. –  Michael Maddox Aug 22 '09 at 11:22
    
I seem to get a far few errors (ranging from closed readers to DON'T USE THESE RECORDS)...did you have any luck in tracking down the problem? –  Kieron Aug 27 '09 at 6:48
3  
What IQueryable is artRepository.FindAllVisibleHeadings() returning? What kind of queries are you adding? I'm pretty sure it coming from that corner. –  Maarten Sep 27 '12 at 13:42
2  
source.Count() is the first time the IQueryable is actually executed. So the executing code is what we do not see in your example code. The error is probably in the artRepository.FindAllVisibleHeadings() method. –  Wouter Simons Sep 27 '12 at 14:31
3  
Just to echo Maarten and Wouter - the error is almost certainly in FindAllVisibleHeadings(). Please add that code to the question. –  Bobson Sep 27 '12 at 14:38
show 2 more comments

6 Answers

I guess the DataContext classes you may be using are tied to a life scope at the request level or at a singleton level. If it is I may suggest you to keep the scope at the method level.

Strange LINQ Exception (See the comments of the answer)

share|improve this answer
    
This would be my guess too. Do a google search for DataContextFactory and you'll find code for a class that can be used to manage the life cycle of a DataContext. I'd personally recommend Request-scoped rather than method-scoped –  smartcaveman Sep 28 '12 at 1:00
    
I approve of this. You are receiving the source as a method parameter, and I suspect you're "caching" the DataContext. This shouldn't be done! In fact the recommended practice is to instantiate a new DataContext every time, the connection management is done under-the-hood by the framework, you shouldn't worry about it. There are lots of questions on SO about this, and MSDN says it too (somewhat implicitly). MSDN on DataContext –  NothingsImpossible Oct 2 '12 at 9:33
add comment

Since you're using IQueryable<T> as source that means that the data are loaded into source parameter only when you call Count() on it.

You can get the first error when calling Single() on a collection with more than one element like this:

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

Given the above, I might say that somewhere in your code you call Single() and in most of the cases the collection has only one element but when it hase more you get the error.

For the second error: looking at the top of the stack trace you see

SqlDataReader.ReadColumnHeader(Int32 i)

which is the method that throws ArgumentOutOfRangeException. This may indicate that your database model is not synchronized with your database schema or the output of your queries i.e. you're expecting to read N columns but instead you have N-K columns.

share|improve this answer
    
I have the problem when running this code: pastebin.com/nuEmuizi And the code sometimes gives the two error messages at random intervals. But what is more weird is that sometimes when the count is not throwing an error - an invalid count value is returned! Very much seems like some sort of database issue or a problem in the sqldatareader. –  Jan Johansen Sep 26 '12 at 10:12
add comment

The only time I've ever seen error one is when i'm trying to set a single object when more than one object was returned.

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

Have you tried including something like this in your pager?

share|improve this answer
    
I'll try that and see if it helps. The worst thing is that this error comes and goes ... and is quite rare. Thanks for the hint though! –  Michal Rogozinski Aug 22 '09 at 19:33
add comment

Looks like you are also going to enumerate the same source twice in a row. Count will run a select * against the db and return a count, then the Take will run another query against the database. You'd be better off getting the results back in an IEnumerable in memory Collection and running .Length on it first and using Take on the IEnumerable to get the results you want for paging. Checking if the length is zero, one, or more you can change if you use Take(), SingleorDefault(), or FirstorDefault()

share|improve this answer
    
Count will do a SELECT COUNT(*) not a SELECT * in any decent LINQ to SQL Provider –  Guillaume86 Oct 1 '12 at 15:18
    
Sorry mistyped, Count (*) is what I meant... my fault –  denas Oct 1 '12 at 15:29
    
Ok, anyway fetching all the data before paging looks like a bad idea to me, Take and Skip will also be translated to SQL, and you'll avoid to load the entire table in memory, your method will get slower as the database grows, a Count then Take/Skip will scale nicely. –  Guillaume86 Oct 1 '12 at 15:34
add comment

Your second exception isn't at the Count(). It is occuring in the AddRange(). And that is most likely occuring where the PageSize exceeds the remaining number of items after skipping. As a note, even if you have reduced the code and are checking that, the count could be inaccurate by the time you run the AddRange.

I would guess that the reason you have to cycle the app pool is because you are re-using the DataContext as Mark has surmised. I would recomend reducing the re-use of the DataContext to at least the request. Then a single error won't bring down the entire application.

share|improve this answer
add comment

The important thing is that even if your exception happens when Count() is executed, the code that is failing is not in that method, but in the LINQ expression that builds your IQueryable. That is all the marvel with LINQ, the LINQ select statement is only executed when its result is enumerated.

An enumerable (queryable inherits enumerable) is enumerated in those following cases (list not exhaustive): Count, Foreach, ToList, ToArray, ToDictionary, First, etc. So when we need an element from or the number of elements in the result.

Even more importantly, as long as you store the result of a LINQ query without converting it to a list or an array, the selecting statement is going to be executed every time you enumerate it.

That being said, here are two important things:

  1. The failing code is in the FindAllVisibleHeadings method, because that's where your LINQ query is built. Without seeing the code it's difficult to know where exactly, but considering the error message you are getting you should look for a Single or SingleOrDefault statement.

  2. There is an obvious code smell in the fact you are enumerating your IQueryable several times (Count and Skip/Take).

The basic solution for that would be to convert your IQueryable to a list before using it.

public PaginatedList(IQueryable<T> 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));
}

But doing this alone would probably not solve your issue. You have to think that anything could happen to your data between the moment you build your LINQ query in the FindAllVisibleHeadings method and the moment you use it.

It would probably be a good idea making FindAllVisibleHeadings return a List instead of an IQueryable. But there is no way to know until we see the code inside it.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.