2011-05-23 8 views
30

En cuanto a mis registros de errores ELMAH, estoy viendo unos InvalidOperationException s de Entity Framework que tienen que ver con:¿Cómo puedo evitar que EF "El contexto no se pueda utilizar mientras se está creando el modelo" de errores?

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

Esto es con la última biblioteca de 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 Windsor, mi unidad EF de la estructura de trabajo está siendo registrado:

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

soy capaz de recrear el error pulsando F5 en VS para comenzar a sesiones de depuración, y mientras IIS está girando carga hasta una segunda página web a la sesión de depuración.

Sospecho que es porque el usuario está tratando de acceder al sistema mientras que Asp.net se ha descargado debido a la falta de actividad, lo cual 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: He actualizado mi controlador de Windsor para contener ahora 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 solicitud Web segunda mientras IIS está cargando la aplicación, el error anterior se sigue produciendo


Edición 2: Conforme a 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) 
+0

Esto es interesante. ¿Puede encontrar más detalles sobre el problema? Una vez que se crea el modelo, se debe bloquear el procesamiento de subprocesos para que el contexto no se use. –

+0

No sé cómo encontrar más detalles sobre esto. Después de que el hilo de depuración de Visual Studio termine de cargarse, ya no veo este error. Solo parece ocurrir en la primera carga de la página web si ocurren dos llamadas simultáneas al mismo tiempo. – KallDrexx

+0

¿Dos llamadas simultáneas? ¿Puedes validar que tienes una instancia nueva del contexto para cada solicitud? –

Respuesta

17

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 de db eran nuevos contextos de db para las solicitudes web específicas. Esto significaba que dos contextos de bases de datos estaban "girando hacia arriba" al mismo tiempo y, por lo tanto, se arrojó este error.

Esto también causó una gran cantidad de problemas de 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 duración de su contexto.


Editar: En respuesta a DotNetWise, que resolvió este forzando mi proveedor de suscripciones personalizado para utilizar siempre una conexión EF de Windsor mediante el almacenamiento de la fábrica de conexiones de Windsor en mi constructor, a continuación, siempre recuperar mi contexto de datos EF de la 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 los lleva a cabo proveedor de pertenencia obtiene la clase UnitOfWork de Windsor, y lo utiliza para realizar la acción (en este caso mi clase UnitOfWork es un soporte repositorio para concluir mi contexto de datos EF)

+0

Gracias, estaba obteniendo esto error y creo que fue porque tenía una variable DataContext global en mis clases personalizadas de proveedor de roles y membresía. – Austin

+0

¿Cuál fue la solución al problema que identificó? ¿Desecha el uso de Windsor para resolver DbContext? –

+3

Lo siento, debería haber incluido eso. Lo resolví haciendo que CADA uno de mis métodos de proveedor de membresía hiciera una nueva solicitud a Windsor para mi DbContext, y nunca usé el mismo DBContext fuera de ese método. Antes de eso, estaba solicitando el DbContext a través del constructor de mi proveedor de membresía y lo estaba almacenando para su posterior mantenimiento, lo que causó el problema. – KallDrexx

7

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

Mi solución era forzar DbContext inicialización del instalador Windsor:

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

podría añadir en mi opinión, esto califica como un error en EF: que debería haber utilizado hilo de seguridad (con cerraduras, o lo que sea) código para la inicialización de DbContext.

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

+0

Llamar 'container.Resolve ()' y hacer una llamada a la base de datos no detiene este problema desafortunadamente. Estoy de acuerdo contigo en que EF debe ser seguro para la inicialización, y es realmente molesto que no lo sea. – KallDrexx

+0

@KallDrexx: lo hace si la inicialización del contenedor en sí misma se realiza de forma segura para la ejecución de subprocesos. Ni siquiera estoy usando la resolución; ese código es parte de mi 'DbInstaller' (una clase que implementa' IWindsorInstaller'') –

+0

Ok Intenté no usar mi unidad de trabajo e interactuar con el 'DbContext'. Ahora mi segunda solicitud fallece con 'El proveedor subyacente falló en Open' en la misma línea de código, así que esto todavía no parece funcionar para mí :( – KallDrexx

3

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

Corregí mi cadena EntityFramework dbconnection y todo estaba bien

Cuestiones relacionadas