30 votes

Comment puis-je éviter les erreurs EF "Le contexte ne peut pas être utilisé pendant la création du modèle"?

En regardant ma Elmah les journaux d'erreur, je vois quelques InvalidOperationExceptions à partir d'Entity Framework qui traitent de:

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

C'est avec la dernière EF CodeFirst bibliothèque de Nuget. La seule information que j'ai pu trouver sur le net, c'est qu'il est causé par le fait d'avoir des données de contextes comme des singletons, qui n'est certainement pas mon cas. Dans mon Windsor installer, ma fe d'unité de la structure de travail est enregistré avec:

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

Je suis en mesure de recréer l'erreur en appuyant sur la touche F5 de VS pour démarrer une sessions de débogage, et alors que IIS est mise en rotation de la charge d'un deuxième page web pour la session de débogage.

Je soupçonne que c'est parce que l'utilisateur tente d'accéder au système pendant Asp.net a déchargé en raison de l'absence d'activité, qui n'a de sens que mon produit est actuellement dans un très très petit test de la bêta. Cependant, dans la réalité, les gens utilisent le site web avec des données en direct, j'ai besoin que peu d'erreurs que possible.

Quelqu'un aurait-il une idée de comment éviter que cela se produise?


Edit:

J'ai mis à jour mon windsor contrôleur à maintenant contenir le code suivant:

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

Cependant, lorsque je tente d'effectuer une 2ème demande web tandis que IIS chargement de l'application, la précédente erreur se produit toujours


Edit 2:

Comme demandé, voici la pile

   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)

17voto

KallDrexx Points 9020

J'ai enfin trouvé la vraie cause de cela, au moins pour moi.

Le problème est que j'ai été récupérer une DbContext de Windsor, dans mon personnalisée Asp.Net fournisseur d'appartenances. Cela a causé un problème parce que le fournisseur d'appartenance a une durée de vie de l'ensemble de l'application, tandis que tous les autres de la récupération des appels pour l'id de contexte ont été db contextes spécifiques pour le web demandes. Cela signifie que la base de données deux contextes ont été "tourne" dans le même temps, et donc cette erreur a été levée.

Cela a également causé beaucoup de difficile à déboguer entité problèmes de mise en cache, donc toute personne qui utilise des EF dans leur adhésion prestataire doit être vraiment prudent à propos de leur contexte de vie.


Modifier

: En réponse à DotNetWise, j'ai résolu ce problème en forçant mon fournisseur d'appartenances personnalisé de toujours utiliser un EF connexion de Windsor, en stockant le Windsor usine de raccordement dans mon constructeur, c'est toujours de la récupération de mon EF données de contexte à partir de l'usine à ce point.

Par exemple:

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

L'idée étant que toute action le fournisseur d'appartenances effectue obtient l' UnitOfWork classe de Windsor, et l'utilise pour effectuer l'action (dans ce cas, mon UnitOfWork classe est un référentiel titulaire de conclure mon EF contexte de données)

7voto

Diego Mijelshon Points 40314

J'ai rencontré le même problème dans une application WPF multithread.

Ma solution de contournement consistait à forcer l'initialisation de DbContext à partir du programme d'installation de Windsor:

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

Je pourrais ajouter à mon avis que cela se qualifie comme un bug dans EF: ils auraient dû utiliser du code thread-safe (avec des verrous, ou autre) pour l'initialisation de DbContext.

Bien sûr, une meilleure solution est ce que fait NHibernate: le SessionFactory est un objet séparé explicitement créé du Session .

3voto

Oladipo Olasemo Points 89

Quand j'ai rencontré ce problème, j'ai trouvé que c'était une connexion db qui avait mal tourné.

J'ai corrigé ma chaîne de connexion DB EntityFramework et tout allait bien

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X