Подтвердить что ты не робот

Как я могу предотвратить использование EF "Невозможно использовать контекст во время создания модели"?

Глядя на мои журналы ошибок Elmah, я вижу несколько InvalidOperationException из Entity Framework, которые имеют дело с:

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

Это последняя библиотека EF CodeFirst от Nuget. Единственная информация, которую я смог найти в сети, заключается в том, что она вызвана наличием контекстов данных в виде синглетов, что, безусловно, не мое дело. В моем установщике Windsor мой модуль работы EF регистрируется с помощью:

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

Я могу воссоздать ошибку, нажав F5 в VS, чтобы начать сеансы отладки, и в то время как IIS разворачивает загрузку второй веб-страницы в сеанс отладки.

Я подозреваю, что это связано с тем, что пользователь пытается получить доступ к системе, когда Asp.net выгружается из-за отсутствия активности, что имеет смысл, так как мой продукт в настоящее время находится в очень маленьком бета-тесте. Однако, поскольку реальные люди используют веб-сайт с живыми данными, мне нужно как можно меньше ошибок.

Кто-нибудь знает, как предотвратить это?


Изменить: Я обновил свой контроллер ветрогенератора, чтобы теперь содержать следующий код:
        container.Register(Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>().LifeStyle.PerWebRequest);
        using (var context = new MyJobLeadsDbContext())
        {
            context.Set<UnitTestEntity>().Any();
        }

Однако, когда я пытаюсь выполнить второй веб-запрос, когда IIS загружает приложение, предыдущая ошибка все еще встречается


Изменить 2: В соответствии с запросом, вот стек
   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)
4b9b3361

Ответ 1

Я, наконец, понял истинную причину этого, по крайней мере для меня.

Проблема заключалась в том, что я извлекал DbContext из Windsor в своем пользовательском провайдере Asp.Net Membership. Это вызвало проблему, потому что у поставщика членства есть срок службы всего приложения, тогда как все другие запросы на поиск для контекста db были новыми контекстами db для конкретных веб-запросов. Это означало, что два контекста базы данных "вращались" одновременно и, таким образом, эта ошибка была брошена.

Это также вызвало много сложностей для отладки проблем кэширования объектов, поэтому каждый, кто использует EF в своем провайдере членства, должен быть очень осторожным в отношении их жизненного цикла.


Изменить. В ответ на DotNetWise я решил это, заставив мой пользовательский поставщик членства всегда использовать EF-соединение из Windsor, сохранив соединение Windsor factory в моем конструкторе, а затем всегда получая мой контекст данных EF из factory в этой точке.

Например:

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

Идея состоит в том, что любое действие, выполняемое поставщиком членства, получает класс UnitOfWork от Windsor и использует его для выполнения действия (в этом случае мой класс UnitOfWork является держателем репозитория для завершения моего контекста данных EF)

Ответ 2

Я столкнулся с той же проблемой в многопоточном приложении WPF.

Мое обходное решение состояло в том, чтобы принудительно инициализировать DbContext у установщика Windsor:

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

Я бы добавил, что это может считаться ошибкой в ​​EF: они должны были использовать поточно-безопасный (с замками или какой-либо) код для инициализации DbContext.

Конечно, лучшим решением является то, что делает NHibernate: SessionFactory - явно созданный отдельный объект из Session.

Ответ 3

Когда я столкнулся с этой проблемой, я обнаружил, что dbconnection пошло не так.

Я исправил строку EntityFramework dbconnection, и все было в порядке