2

I am intermittently getting an System.InvalidCastException: Specified cast is not valid. error in my repository layer when performing an abstracted SELECT query mapped with LINQ.

The error can't be caused by a mismatched database schema since it works intermittently and it's on my local dev machine.

Could it be because StructureMap is caching the data context between page requests? If so, how do I tell StructureMap v2.6.1 to inject a new data context argument into my repository for each request?

Update: I found this question which correlates my hunch that something was being re-used. Looks like I need to call Dispose on my injected data context. Not sure how I'm going to do this to all my repositories without copypasting a lot of code.

Edit: These errors are popping up all over the place whenever I refresh my local machine too quickly. Doesn't look like it's happening on my remote deployment box, but I can't be sure.

I changed all my repositories' StructureMap life cycles to HttpContextScoped() and the error persists.

Code:

public ActionResult Index()
{
    // error happens here, which queries my page repository
    var page = _branchService.GetPage("welcome"); 
    if (page != null)
    ViewData["Welcome"] = page.Body;
    ...
}

Repository:

GetPage boils down to a filtered query mapping in my page repository.

public IQueryable<Page> GetPages()
{
    var pages = from p in _db.Pages
        let categories = GetPageCategories(p.PageId)
        let revisions = GetRevisions(p.PageId)
        select new Page
        {
            ID = p.PageId,
            UserID = p.UserId,
            Slug = p.Slug,
            Title = p.Title,
            Description = p.Description,
            Body = p.Text,
            Date = p.Date,
            IsPublished = p.IsPublished,
            Categories = new LazyList<Category>(categories),
            Revisions = new LazyList<PageRevision>(revisions)
        };

        return pages;
}

where _db is an injected data context as an argument, stored in a private variable which I reuse for SELECT queries.

Calling code:

public Page GetPage(string slug)
{
    return _pageRepository.GetPages()
                          .WithSlug(slug).FirstOrDefault();
}

WithSlug is just a pipeline filter that adds a where clause to the query.

Error:

Specified cast is not valid.
Exception Details: System.InvalidCastException: Specified cast is not valid.

Stack Trace:

[InvalidCastException: Specified cast is not valid.]
   System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult) +4539
   System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) +207
   System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) +500
   System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute(Expression expression) +50
   System.Linq.Queryable.FirstOrDefault(IQueryable`1 source) +383
   Manager.Controllers.SiteController.Index() in C:\Projects\Manager\Manager\Controllers\SiteController.cs:68
   lambda_method(Closure , ControllerBase , Object[] ) +79
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +258
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
   System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +125
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +640
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +312
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +709
   System.Web.Mvc.Controller.ExecuteCore() +162
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +58
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +453
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +371
Community
  • 1
  • 1
Petrus Theron
  • 27,855
  • 36
  • 153
  • 287
  • Show us the code and some stack trace. It might help. – Steven Jan 17 '11 at 11:30
  • @Steven, updated question with stack trace and code. This specific table and model has not changed for months. It is not isolated to this though - I'm getting this error all over the place. It feels like a data context is being held in memory and after a few seconds a new one is injected, allowing a query to succeed. – Petrus Theron Jan 17 '11 at 11:42
  • What is happening in the `GetPageCategories` and `GetRevisions` methods. Af far as I know, you can't call native .NET methods when LINQ to SQL has no direct mapping. Did you happen to refactor sub queries of that LINQ query into those methods? – Steven Jan 17 '11 at 12:50
  • btw. Where is the code that calls the `FirstOrDefault` method that I see in your stack trace. There is some code missing. – Steven Jan 17 '11 at 12:51
  • @Steven, those are refactored as subqueries with the `let` keyword. I've added the calling code for you. – Petrus Theron Jan 17 '11 at 13:12
  • @FreshCode: Undo that refactoring and place the sub queries right into that LINQ query, because that will be your problem. There's no LINQ provider (except LINQ to Objects) that is able to translate such a query. – Steven Jan 17 '11 at 14:36
  • @Steven, I know the limitations of subqueries with LINQ-to-SQL. These are lazy-executed one-by-one when iterating over the IQueryable and have always worked perfectly. When subqueries fail, I resort to views. The same error I describe here is caused by a methods that use no subqueries whatsoever. – Petrus Theron Jan 18 '11 at 11:08
  • @FreshCode: I'm sorry. You are right. Your use of method calls in the query is a special case where LINQ to SQL is smart enough to run the calls within the `select`. It will fail if you use `categories` or `revisions` in a `where` clause. I learned something today :-) – Steven Jan 18 '11 at 11:21
  • @Steven, even though it worked in the past, I think the problem *is* related to subqueries. If I wrap a subquery SELECT in a `using (DB db = new DB() { ... }`, I get a "cannot access disposed DataContext" as expected, and without it I get the dreaded "specified cast invalid". The error seems most common with nested queries. I can get rid of the `let` clauses, but I'll have a A LOT of repeated code to map child objects. – Petrus Theron Jan 19 '11 at 09:04

1 Answers1

0

Messing around with disposing repositories didn't help, but setting MultipleActiveResultsets to true in my SQL connection string solved the problem.

Petrus Theron
  • 27,855
  • 36
  • 153
  • 287