1

I am very new to entity framework and I am having a problem with a web api based site (connected to mssql) that I am writing. I keep getting seemingly random errors (mostly seeming to be database related). These errors happen most often when the site is first published but they do sometimes happen when it has been hours since the last publish. A selection of the errors:

  • Invalid operation. The connection is closed.
  • There is already an open DataReader associated with this Command which must be closed first.
  • The connection was not closed. The connection's current state is connecting.
  • The context cannot be viewed while the model is being created
  • Underlying provider failed to open

My context looks like this:

public class Context : DbContext
{

    public Context() : base("name=DefaultConnection")
    {
    }

    public override int SaveChanges()
    {
        DateTime now = DateTime.Now;
        foreach (ObjectStateEntry entry in (this as IObjectContextAdapter).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
        {
            if (!entry.IsRelationship)
            {
                IHasUpdated updated = entry.Entity as IHasUpdated;
                if (updated != null)
                    updated.updated = now;
            }
        }
        return base.SaveChanges();
    }

    public DbSet<Branch> Branches { get; set; }
    public DbSet<Company> Companies { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<UsefulLink> UsefulLinks { get; set; }
}

There are many more DbSets than this. Should I be creating a separate context for each?

One of my basic controllers:

 public class UsefulLinksController : ApiController
 {
    private Context db = new Context();

    [ResponseType(typeof(UsefulLinksWrapper))]
    public IHttpActionResult GetUsefulLinks([FromUri]UsefulLinkParams prams)
    {   
        UsefulLinksWrapper wrapper = new UsefulLinksWrapper();
        Meta meta = new Meta();
        IQueryable<UsefulLink> query = db.UsefulLinks;

    if (prams.sortBy == null)
        {
            prams.sortBy = "ID";
        }

        // Paging
        query = query.OrderBy(prams.sortBy + " " + prams.sortDirection).Skip(prams.offset - 1).Take(prams.limit);

        List<UsefulLink> data = query.ToList();

        meta.totalCount = query.Count();
        meta.offset = 1;
        meta.limit = prams.limit;
        wrapper.meta = meta;
        wrapper.data = data;

        return Ok(wrapper);

    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool UsefulLinkExists(int id)
    {
        return db.UsefulLinks.Count(e => e.ID == id) > 0;
    }
}

I don't seem to see these errors when I run the site locally though there are two of us hitting it when it is published so perhaps the issue stems from multiple users?

chiccodoro
  • 13,709
  • 16
  • 83
  • 129
Chris Foot
  • 193
  • 3
  • 15
  • What is the lifecycle of db context? It should be per request. – prnjanuario May 01 '14 at 11:25
  • 1
    Set MultipleActiveResultSets=True in the connection string and make sure not a single context instance is accessed by multiple threads (which may occur if you share context instances among controllers). – Gert Arnold May 01 '14 at 11:49
  • @prnjanuario I don't know! How do I find out. – Chris Foot May 01 '14 at 18:04
  • @GertArnold Unfortunately, the connection string addition is the first thing I tried and it hasn't seemed to make any difference. Mine is in a different case to yours though so i'll make sure that isn't the problem! – Chris Foot May 01 '14 at 18:05
  • You should try to narrow down your problem as much as possible. Try to find the smallest piece of code that still reproduces the issue. Ideally it is so small you can post it completely here - if you haven't found the root cause in the process of shrinking your code. Examples: Does it still happen if you only have one DbSet? Does it happen if you use the entities from a command line project rather than an MVC? ... – chiccodoro May 12 '14 at 10:33

2 Answers2

9

Chris, I notice in your controller you are sharing your db context with all of the methods in your controller class.

This is generally not a best practice in Entity Framework (see: EntityFramework 4 ObjectContext Lifetime). You should keep your context alive as briefly as possible. Leaving the context alive to share across multiple methods could result in many of the errors that you list above.

I would recommend trying to instantiate a new instance of the context, instead, wherever it is used and quickly disposing of it.

This should generally result in more stable behavior.

So the below:

class SomeClass
{
   private context = new Context(); //sharing your context with all methods
   public someMethod()
   {
      context.doSomething;
   }

   public someMethod2()
   {
      context.doSomething;
   }
}

should become:

class SomeClass
{

   public someMethod()
   {
      Context context = new Context(); //now your context is declared and disposed of within each method
      context.doSomething;
   }

   public someMethod2()
   {
      Context context = new Context(); //now your context is declared and disposed of within each method
      context.doSomething;
   }
}

Or even better, you can use a using construct to ensure that your context is properly disposed of:

class SomeClass
{
   public someMethod3()
   {
      using(Context context = new Context()) //now wrapping the context in a using to ensure it is disposed
      {
         context.doSomething;
      }
   }
}

I would recommend trying the above changes and seeing if your behavior becomes more stable.

Community
  • 1
  • 1
Ayo I
  • 6,642
  • 4
  • 24
  • 37
1

Since I do not know how your page uses the methods UsefulLinksController and in which order, I would say UsefulLinkExists is perhaps the culprit due to lazy loading

Lazy loading means delaying the loading of related data until you specifically request it

Which would explain why your "reader" remains "open".

Try:

return db.UsefulLinks.ToList().Count(e => e.ID == id) > 0;

In any case, you can disable lazy loading by default in the context constructor as such noted here:

public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext")
{
    this.ContextOptions.LazyLoadingEnabled = false;
    OnContextCreated();
}

As far as I know, it applies to EF4 and up.

Community
  • 1
  • 1
Francis Ducharme
  • 4,277
  • 5
  • 32
  • 66
  • I didn't think that lazy loading would be happening here as none of the linked properties are set to virtual on any of my models. I don't want lazy loading anywhere in the project as it causes us problems when json serializing, would I need to specifically turn it off? I am using include wherever I want linked entities. – Chris Foot May 01 '14 at 18:08
  • @ChrisFoot I don't know if there is any way to turn it off via the model settings or such, but I have encountered this issue many times, albeit in different situations and doing `ToList()` usually solved the issue for the reasons mentioned above. – Francis Ducharme May 12 '14 at 11:25
  • I disabled lazy loading globally using the code from the accepted answer on the link but it is still happening unfortunately. – Chris Foot May 12 '14 at 13:57
  • I've now tried the solution from ssmith as well and confirmed that lazy loading is definitely disabled in debug and the issue is still happening – Chris Foot May 12 '14 at 14:01
  • @ChrisFoot Are the errors happening during read or write operations or both ? – Francis Ducharme May 12 '14 at 14:03
  • Well it's definitely happening during read operations. It's difficult to test write operations because it only happens on the first few requests and our pages all do a few requests when they first load. I'm certain it's not a multiple user thing now too. It's almost like the first access to everything is causing the application to start or something weird like that. – Chris Foot May 12 '14 at 14:14
  • @ChrisFoot It's kind of hard for us then. Perhaps provide more info on how your application starts (`Application_Start`) if it's got any custom code in it and what happens when the user browses the homepage for the first time. – Francis Ducharme May 13 '14 at 14:37