Я уже несколько дней возился со следующим.EntityFramework Жизненный цикл DbContext + Postgres: «Операция уже выполняется».
У меня есть приложение Nancy, работающее на Mono, с EntityFramework с шаблоном репозитория и UnitOfWork и Postgres. Нэнси использует TinyIoC, поскольку это контейнер IoC.
У меня есть веб-приложение, которое ставит в очередь запросы на интерфейсе, так что на задний план попадает один запрос за раз. Все это прекрасно работает.
Однако проблема возникает, когда я запускаю приложение iOS, которое подключается к одному и тому же серверному серверу, и не ставит в очередь запросы к серверу, иногда обстреливая запрос.
В случайных интервалах бэкенд начинает бросать эту ошибку:
2016-09-20T13:30:16.120057436Z app[web.1]: System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.InvalidOperationException: An operation is already in progress.
2016-09-20T13:30:16.120104535Z app[web.1]: at Npgsql.NpgsqlConnector.StartUserAction (ConnectorState newState) <0x41ad0150 + 0x00313> in <filename unknown>:0
2016-09-20T13:30:16.120113254Z app[web.1]: at Npgsql.NpgsqlCommand.ExecuteDbDataReaderInternal (CommandBehavior behavior) <0x41acfe30 + 0x0002f> in <filename unknown>:0
2016-09-20T13:30:16.120119308Z app[web.1]: at Npgsql.NpgsqlCommand.ExecuteDbDataReader (CommandBehavior behavior) <0x41acfe00 + 0x00013> in <filename unknown>:0
2016-09-20T13:30:16.120125313Z app[web.1]: at System.Data.Common.DbCommand.ExecuteReader (CommandBehavior behavior) <0x41f1a3c0 + 0x00018> in <filename unknown>:0
2016-09-20T13:30:16.120131185Z app[web.1]: at (wrapper remoting-invoke-with-check) System.Data.Common.DbCommand:ExecuteReader (System.Data.CommandBehavior)
2016-09-20T13:30:16.120206045Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c (System.Data.Common.DbCommand t, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext`1 c) <0x41f1ac20 + 0x00027> in <filename unknown>:0
2016-09-20T13:30:16.120220450Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1[TInterceptor].Dispatch[TTarget,TInterceptionContext,TResult] (System.Data.Entity.Infrastructure.Interception.TTarget target, System.Func`3 operation, System.Data.Entity.Infrastructure.Interception.TInterceptionContext interceptionContext, System.Action`3 executing, System.Action`3 executed) <0x41b1d3c0 + 0x0010e> in <filename unknown>:0
2016-09-20T13:30:16.120232740Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader (System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) <0x41f1a880 + 0x00263> in <filename unknown>:0
2016-09-20T13:30:16.120267802Z app[web.1]: at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader (CommandBehavior behavior) <0x41f1a3f0 + 0x000e6> in <filename unknown>:0
2016-09-20T13:30:16.120274613Z app[web.1]: at System.Data.Common.DbCommand.ExecuteReader (CommandBehavior behavior) <0x41f1a3c0 + 0x00018> in <filename unknown>:0
2016-09-20T13:30:16.120318116Z app[web.1]: at (wrapper remoting-invoke-with-check) System.Data.Common.DbCommand:ExecuteReader (System.Data.CommandBehavior)
2016-09-20T13:30:16.120326788Z app[web.1]: at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands (System.Data.Entity.Core.EntityClient.EntityCommand entityCommand, CommandBehavior behavior) <0x41f154c0 + 0x00043> in <filename unknown>:0
2016-09-20T13:30:16.120332587Z app[web.1]: --- End of inner exception stack trace ---
2016-09-20T13:30:16.120336995Z app[web.1]: at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands (System.Data.Entity.Core.EntityClient.EntityCommand entityCommand, CommandBehavior behavior) <0x41f154c0 + 0x000b3> in <filename unknown>:0
2016-09-20T13:30:16.120344218Z app[web.1]: at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType] (System.Data.Entity.Core.Objects.ObjectContext context, System.Data.Entity.Core.Objects.ObjectParameterCollection parameterValues) <0x41f11e50 + 0x000a4> in <filename unknown>:0
Я регистрирующая зависимость, как к, в загрузчике Нэнси:
protected override void ConfigureApplicationContainer (TinyIoCContainer container)
{
base.ConfigureApplicationContainer (container);
Database.SetInitializer<ReflectDbContext> (new NullDatabaseInitializer<ReflectDbContext>()); // add this to allow prevent "The context cannot be used while the model is being created"
container.Register<IReflectDbContext, ReflectDbContext>();
container.Register<ReflectUnitOfWork>().AsSingleton();
container.Register<IReflectUserRepository, ReflectUserRepository>();
container.Register<IUserRepository<ReflectUser>, ReflectUserRepository>();
container.Register<IReviewRepository, ReviewRepository>();
container.Register<IReviewSetupRepository, ReviewSetupRepository>();
container.Register<IRepositoryV2<ReflectUserActivityItem>, EntityFrameworkRepository<ReflectUserActivityItem>>();
container.Register<IAuthenticationUnitOfWork<ReflectUser, ReflectUserActivityItem>, ReflectUnitOfWork>();
container.Register<IRepository<ReflectUserActivityItem>, NullRepository<ReflectUserActivityItem>>(); //TODO remove this when port is complete
container.Register<IErrorLogger, SimpleLogLogger>();
container.Register<IGeoIpDataProvider, TelizeGeoIpDataProvider>();
container.Register<IRepository<ReviewSetup>, ServiceStackOrmLiteRepository<ReviewSetup>>();
container.Register<IEmailExporter, MailChimpUserEmailDataExporter>();
container.Register<IMailer, SmtpMailer>();
container.Register<IUserManager<ReflectUser>, UserManager<ReflectUser, ReflectUserActivityItem>>();
container.Register<IUserMessageManager<ReflectUser>, UserMessageManager<ReflectUser>>();
etc...
}
У меня есть ощущение, что это мульти -threading и что два отдельных запроса используют один и тот же DbContext (или базовое соединение), из-за чего вещи могут взорваться.
Я уже пробовал зарегистрироваться в методе ConfigureRequestContainer
загрузчика Nancy, но это исключает исключение «Connection is not open».
Теория позади этого вопроса четко изложена в этой статье: http://mehdi.me/ambient-dbcontext-in-ef6/
Следующая неясно мне:
- Я правильно предполагая, что это многопоточность вопрос?
- Мне нужно знать правильный способ убедиться, что каждый запрос использует собственный DbContext/connection, поэтому материал не сталкивается, используя TinyIoC/Nancy, чтобы управлять жизненным циклом DbContext.
Я понимаю, что это сложная проблема. Дайте мне знать, если вам нужна дополнительная информация.
Спасибо :-).
Да, это, скорее всего, единственный DbContext используется несколькими потоками. Зарегистрируйте DbContext в своем контейнере как новый экземпляр для каждого запроса, чтобы каждый экземпляр создавался каждый раз, когда вы его разрешаете. – Evk
Я регистрирую DbContext так: 'container.Register();' Если я правильно понимаю документы TinyIoC, это должно регистрировать DbContext и multi-instance и давать новый экземпляр каждый раз, когда он разрешен. Вот как я это настроил в данный момент и что вызывает вышеупомянутую ситуацию. Таким образом, это означает, что, хотя это multi-instance, это не гарантирует новый экземпляр каждого запроса? –
Corstiaan
По умолчанию он не будет регистрировать интерфейсы как одиночные, поэтому каждый раз возвращается один и тот же экземпляр, что вызывает проблему, которую вы наблюдаете. Сделайте container.Register(). AsMultiInstance() зарегистрируется как мультиэкземпляр. –
Evk