Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I prevent EF "The context cannot be used while the model is being created" errors?

Looking at my Elmah error logs, I am seeing a few InvalidOperationExceptions from Entity Framework that deal with:

The context cannot be used while the model is being created. 

This is with the latest EF CodeFirst library from Nuget. The only information I have been able to find on the net is that it is being caused by having data contexts as singletons, which is most certainly not my case. In my Windsor installer, my EF unit of work structure is being registered with:

container.Register(Component.For<IUnitOfWork>()                             .ImplementedBy<EFUnitOfWork>()                             .LifeStyle                             .PerWebRequest); 

I am able to recreate the error by hitting F5 in VS to start a debugging sessions, and while IIS is spinning up load up a second webpage to the debug session.

I suspect it is because the user is trying to access the system while Asp.net has unloaded due to the lack of activity, which makes sense as my product is currently in a very very small beta test. However, since real people are using the website with live data, I need as little errors occurring as possible.

Does anyone have any idea how to prevent this from occurring?


Edit: I updated my windsor controller to now contain the following code:
        container.Register(Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>().LifeStyle.PerWebRequest);         using (var context = new MyJobLeadsDbContext())         {             context.Set<UnitTestEntity>().Any();         } 

However, when I attempt to perform a 2nd web request while IIS is loading the application, the previous error still occurs


Edit 2: As requested, here is the stack
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()    at System.Data.Entity.Internal.InternalContext.Initialize()    at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)    at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()    at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()    at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()    at System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate)    at MyApp.DomainModel.Queries.Users.UserByEmailQuery.Execute() in C:\Users\KallDrexx\Documents\Projects\MyApp\MyApp.DomainModel\Queries\Users\UserByEmailQuery.cs:line 44    at MyApp.Infrastructure.MyAppMembershipProvider.GetUser(String email, Boolean userIsOnline) in C:\Users\KallDrexx\Documents\Projects\MyApp\MyApp\Infrastructure\MyAppMembershipProvider.cs:line 102    at System.Web.Security.Membership.GetUser(String username, Boolean userIsOnline)    at System.Web.Security.Membership.GetUser()    at MyApp.MyAppBaseController.Initialize(RequestContext requestContext) in C:\Users\KallDrexx\Documents\Projects\MyApp\MyApp\MyAppBaseController.cs:line 23    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.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()    at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()    at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)    at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()    at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()    at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)    at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)    at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)    at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)    at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 
like image 958
KallDrexx Avatar asked May 23 '11 16:05

KallDrexx


People also ask

What is context in EF?

The context class is a most important class while working with EF 6 or EF Core. It represent a session with the underlying database using which you can perform CRUD (Create, Read, Update, Delete) operations. The context class in Entity Framework is a class which derives from System.

Should you use using with DbContext?

EF and EF Core DbContext types implement IDisposable . As such, best practice programming suggests that you should wrap them in a using() block (or new C# 8 using statement). Unfortunately, doing this, at least in web apps, is generally a bad idea.

How do I create a context class in Entity Framework?

To use code-first for an existing database, right click on your project in Visual Studio -> Add -> New Item.. Select ADO.NET Entity Data Model in the Add New Item dialog box and specify the model name (this will be a context class name) and click on Add. This will open the Entity Data Model wizard as shown below.


1 Answers

I finally figured out the true cause of this, at least for me.

The issue was that I was retrieving a DbContext from Windsor in my custom Asp.Net Membership provider. This caused an issue because the membership provider has a lifespan of the whole application, while all other retrieval calls for the db context were new db contexts for the specific web requests. This meant that two database contexts were "spinning up" at the same time and thus this error was thrown.

This also caused a lot of hard to debug entity caching issues as well, so anyone who uses EF in their membership provider needs to be real careful about their context lifetime.


Edit: In response to DotNetWise, I solved this by forcing my custom membership provider to always use an EF connection from Windsor by storing the Windsor connection factory in my constructor, then always retrieving my EF data context from the factory at that point.

For example:

public class CustomMembershipProvider : MembershipProvider {     private IServiceFactory _serviceFactory;      public CustomMembershipProvider() : this(null) { }      public CustomMembershipProvider(IServiceFactory factory)     {         // IF no factory was provided, we need to get one from the bootstrapper         if (factory == null)             _serviceFactory = new WindsorServiceFactory(Bootstrapper.WindsorContainer);         else             _serviceFactory = factory;     }      public override string ResetPassword(string email, string answer)     {         var unitOfWork = GetUnitOfWork();         return new ResetUserPasswordCommand(unitOfWork).WithUserEmail(email).Execute();     }      private IUnitOfWork GetUnitOfWork()     {        return _serviceFactory.GetService<IUnitOfWork>();     } } 

The idea being that any action the membership provider performs gets the UnitOfWork class from Windsor, and uses that to perform the action (in this case my UnitOfWork class is a repository holder to wrap up my EF data context)

like image 134
KallDrexx Avatar answered Oct 25 '22 05:10

KallDrexx