c# entity-framework ef-code-first entity-framework-4.1

c# - ¿Cómo puedo evitar que EF "El contexto no se pueda usar mientras se está creando el modelo" errores?



entity-framework ef-code-first (3)

Cuando encontré este problema, descubrí que se trataba de una conexión incorrecta que salió mal.

Corregí mi cadena EntityFramework dbconnection y todo estaba bien

Al mirar mis registros de errores de Elmah, veo algunas InvalidOperationException de Entity Framework que tratan de:

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

Esto es con la última biblioteca EF CodeFirst de Nuget. La única información que he podido encontrar en la red es que está siendo causada por tener contextos de datos como singletons, que ciertamente no es mi caso. En mi instalador de Windsor, mi estructura de unidad de trabajo EF está siendo registrada con:

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

Puedo recrear el error presionando F5 en VS para iniciar las sesiones de depuración, y mientras IIS está activando la carga de una segunda página web en la sesión de depuración.

Sospecho que se debe a que el usuario está intentando acceder al sistema mientras Asp.net se ha descargado debido a la falta de actividad, lo que tiene sentido ya que mi producto se encuentra actualmente en una prueba beta muy pequeña. Sin embargo, dado que la gente real está usando el sitio web con datos en vivo, necesito que ocurran los menos errores posibles.

¿Alguien tiene alguna idea de cómo evitar que esto ocurra?

Editar: actualicé mi controlador windsor para ahora contener el siguiente código:

container.Register(Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>().LifeStyle.PerWebRequest); using (var context = new MyJobLeadsDbContext()) { context.Set<UnitTestEntity>().Any(); }

Sin embargo, cuando intento realizar una segunda solicitud web mientras IIS está cargando la aplicación, aún se produce el error anterior

Edición 2: según lo solicitado, aquí está la pila

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)


Finalmente descubrí la verdadera causa de esto, al menos para mí.

El problema era que estaba recuperando un DbContext de Windsor en mi proveedor de membresía Asp.Net personalizado. Esto causó un problema porque el proveedor de membresía tiene una vida útil de toda la aplicación, mientras que todas las demás llamadas de recuperación para el contexto db eran nuevos contextos db para las solicitudes web específicas. Esto significaba que dos contextos de base de datos estaban "girando" al mismo tiempo y, por lo tanto, se produjo este error.

Esto también causó muchos problemas de almacenamiento en caché de entidades difíciles de depurar, por lo que cualquier persona que use EF en su proveedor de membresía debe tener mucho cuidado con la vida del contexto.

Editar : En respuesta a DotNetWise, resolví esto forzando a mi proveedor de membresía personalizado a usar siempre una conexión EF de Windsor almacenando la fábrica de conexiones de Windsor en mi constructor, y luego siempre recuperando el contexto de datos de EF de fábrica en ese punto.

Por ejemplo:

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>(); } }

La idea es que cualquier acción que realice el proveedor de membresía obtiene la clase UnitOfWork de Windsor, y la utiliza para realizar la acción (en este caso, mi clase UnitOfWork es un titular del repositorio para UnitOfWork mi contexto de datos EF)


Me encontré con el mismo problema en una aplicación WPF multiproceso.

Mi solución fue forzar la inicialización de DbContext desde el instalador de Windsor:

container.Register(Component.For(TheDbContext.Blah.Blah)); using (var context = new TheDbContext()) context.Set<SomeRandomEntity>().Any();

En mi opinión, podría agregar que esto califica como un error en EF: deberían haber usado código seguro para subprocesos (con bloqueos, o lo que sea) para la inicialización de DbContext.

Por supuesto, una mejor solución es lo que hace NHibernate: SessionFactory es un objeto separado explícitamente creado de la Session .