如何防止 EF“创建模型时无法使用上下文”错误?
查看我的 Elmah 错误日志,我看到实体框架中的一些 InvalidOperationException
处理:
The context cannot be used while the model is being created.
这是来自 Nuget 的最新 EF CodeFirst 库。我在网上找到的唯一信息是,它是由数据上下文作为单例引起的,这肯定不是我的情况。在我的 Windsor 安装程序中,我的 EF 工作单元结构正在注册:
container.Register(Component.For<IUnitOfWork>()
.ImplementedBy<EFUnitOfWork>()
.LifeStyle
.PerWebRequest);
我可以通过在 VS 中按 F5 启动调试会话来重新创建错误,并且在 IIS 旋转时将第二个网页加载到调试会话。
我怀疑这是因为用户正在尝试访问系统,而 Asp.net 由于缺乏活动而已卸载,这是有道理的,因为我的产品目前正在进行非常小的 Beta 测试。但是,由于真实的人正在使用带有实时数据的网站,因此我需要尽可能少地发生错误。
有谁知道如何防止这种情况发生?
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();
}
但是,当我在 IIS 加载应用程序时尝试执行第二个 Web 请求时,仍然会出现之前的错误
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)
Looking at my Elmah error logs, I am seeing a few InvalidOperationException
s 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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我终于弄清楚了真正的原因,至少对我来说是这样。
问题是我正在自定义 Asp.Net 会员资格提供程序中从 Windsor 检索
DbContext
。这导致了一个问题,因为成员资格提供程序具有整个应用程序的生命周期,而数据库上下文的所有其他检索调用都是特定 Web 请求的新数据库上下文。这意味着两个数据库上下文同时“旋转”,因此引发了此错误。这也导致了许多难以调试的实体缓存问题,因此在成员资格提供程序中使用 EF 的任何人都需要非常小心其上下文生命周期。
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.
例如:
这个想法是,会员资格提供者执行的任何操作都会从 Windsor 获取
UnitOfWork
类,并使用它来执行操作(在本例中,我的UnitOfWork
类是存储库持有者来包装我的 EF 数据上下文)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:
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 myUnitOfWork
class is a repository holder to wrap up my EF data context)我在多线程 WPF 应用程序中遇到了同样的问题。
我的解决方法是强制从 Windsor 安装程序初始化 DbContext:
在我看来,我可能会补充说这属于 EF 中的错误:他们应该使用线程安全(带锁或其他)代码来进行 DbContext 初始化。
当然,更好的解决方案是 NHibernate 所做的:SessionFactory 是一个显式创建的、独立于 Session 的对象。
I ran into the same issue in a multithreaded WPF app.
My workaround was to force DbContext initialization from the Windsor installer:
I might add in my opinion this qualifies as a bug in EF: they should have used thread-safe (with locks, or whatever) code for DbContext initialization.
Of course, a better solution is what NHibernate does: the
SessionFactory
is an explicitly created, separate object from theSession
.当我遇到这个问题时,我发现这是一个数据库连接出错。
我更正了 EntityFramework dbconnection 字符串,一切都很好
When i encountered this issue, i found it was a dbconnection gone wrong.
I corrected my EntityFramework dbconnection string and all was fine