We have the following code in EntityFrameworkCoreModule.cs:
public override void PostInitialize()
{
var configurationAccessor = IocManager.Resolve<IAppConfigurationAccessor>();
EnsureMigrated();
using (var scope = IocManager.CreateScope())
{
if (!SkipDbSeed && scope.Resolve<DatabaseCheckHelper>().Exist(configurationAccessor.Configuration["ConnectionStrings:Default"]))
SeedHelper.SeedHostDb(IocManager);
}
}
private void EnsureMigrated()
{
using (var migrateExecuter = IocManager.ResolveAsDisposable<MultiTenantMigrateExecuter>())
{
migrateExecuter.Object.Run();
}
}
The MultiTenantMigrateExecuter.Run() performs an AbpZeroDbMigrator.CreateOrMigrateForHost(SeedHelper.SeedHostDb).
This has worked fine. However after updrading to the latest Zero version 6.7.0 we have stumbled into some problems.
The API stops at boot with the following error: SqlException: Invalid column name 'SubscriptionPaymentType'.
This happens before the migration occurs. So it seems the boot process requires the migration to be run before boot and PostInitialize is then too late.
Running a manual database update work, but this makes out CI/CD in Azure Devops to stop working.
Any ideas how to make the migration happen before the startup boot?
9 Answer(s)
-
0
Hi, can you share if you are using .net framework or .net core?
Also can you share the full stacktrace of the SqlException?
-
0
Hi.
Core version 2.2 (Angular+API)
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'SubscriptionPaymentType'. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext() at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found) at lambda_method(Closure ) at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext() at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found) at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc) at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate) at Castle.Proxies.Invocations.IRepository`2_FirstOrDefault.InvokeMethodOnTarget() at Castle.DynamicProxy.AbstractInvocation.Proceed() at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options) at Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.Proxies.IRepository`1Proxy.FirstOrDefault(Int32 id) at Abp.MultiTenancy.TenantCache`2.GetTenantOrNull(Int32 tenantId) at Castle.Proxies.Invocations.TenantCache`2_GetTenantOrNull.InvokeMethodOnTarget() at Castle.DynamicProxy.AbstractInvocation.Proceed() at Abp.Domain.Uow.UnitOfWorkInterceptor.PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options) at Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.Proxies.TenantCache`2Proxy.GetTenantOrNull(Int32 tenantId) at Abp.MultiTenancy.TenantCache`2.<>c__DisplayClass7_0.<GetOrNull>b__0() at Abp.Runtime.Caching.CacheExtensions.<>c__DisplayClass5_0`2.<Get>b__0(String k) at Abp.Runtime.Caching.CacheBase.Get(String key, Func`2 factory) at Abp.Runtime.Caching.CacheExtensions.Get[TKey,TValue](ICache cache, TKey key, Func`2 factory) at Castle.Proxies.Invocations.ITenantCache_GetOrNull.InvokeMethodOnTarget() at Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.Proxies.TenantCache`2Proxy.GetOrNull(Int32 tenantId) at Abp.MultiTenancy.TenantStore.Find(Int32 tenantId) at Abp.Configuration.SettingManager.<>c__DisplayClass41_0.<<GetTenantSettingsFromCache>b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Abp.Runtime.Caching.CacheExtensions.<>c__DisplayClass9_0`2.<<GetAsync>b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Abp.Runtime.Caching.CacheBase.GetAsync(String key, Func`2 factory) at Abp.Runtime.Caching.CacheExtensions.GetAsync[TKey,TValue](ICache cache, TKey key, Func`2 factory) at Abp.Configuration.SettingManager.GetTenantSettingsFromCache(Int32 tenantId) at Abp.Configuration.SettingManager.GetReadOnlyTenantSettings(Int32 tenantId) at Abp.Configuration.SettingManager.GetSettingValueForTenantOrNullAsync(Int32 tenantId, String name) at Abp.Configuration.SettingManager.GetSettingValueInternalAsync(String name, Nullable`1 tenantId, Nullable`1 userId, Boolean fallbackToDefault) at Abp.Configuration.SettingManagerExtensions.GetSettingValueAsync[T](ISettingManager settingManager, String name) at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task`1 task) at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location where exception was thrown --- at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) --- End of stack trace from previous location where exception was thrown --- at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task`1 task) at Nito.AsyncEx.AsyncContext.Run[TResult](Func`1 action) at Integration.GHRIntegrationModule.PostInitialize() in F:\a\1\s\aspnet-core\src\Integration\GHRIntegrationModule.cs:line 73 at System.Collections.Generic.List`1.ForEach(Action`1 action) at Abp.AbpBootstrapper.Initialize() at Abp.AspNetCore.AbpApplicationBuilderExtensions.InitializeAbp(IApplicationBuilder app) at Abp.AspNetCore.AbpApplicationBuilderExtensions.UseAbp(IApplicationBuilder app, Action`1 optionsAction) at Web.Startup.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) in F:\a\1\s\aspnet-core\src\Web.Host\Startup\Startup.cs:line 154 --- End of stack trace from previous location where exception was thrown ---
-
0
In the stack trace there is a reference to GHRIntegrationModule.PostInitialize. I wasa afraid that the module was loaded in the wrong order, but adding [DependsOn(typeof(EntityFrameworkCoreModule))] did not change anything. The exception still occurs and the stack trace remains the same.
The mentioned line in the PostInitialize (row 73) is the following: var activeDirectoryServerName = configurationAccessor.Configuration["Integration:ActiveDirectoryServerName"]; I fail to see how that line would affect EF though.
-
0
Can you share the code in
GHRIntegrationModule/PostInitialize()
which callsSettingManager.GetSettingValueAsync()
Also you might want to consider moving
EnsureMigrated()
intoYourProjectEntityFrameworkCoreModule
-
0
GHRIntegrationModule:
public override void PostInitialize() { var configurationAccessor = IocManager.Resolve<IAppConfigurationAccessor>(); #region Integration:ActiveDirectoryServer var activeDirectoryServerName = configurationAccessor.Configuration["Integration:ActiveDirectoryServerName"]; SettingManager settingsManager = IocManager.Resolve<SettingManager>(); if (settingsManager.GetSettingValue<bool>(LdapSettingNames.IsEnabled)) { // Use AD reader IocManager.Register<IActiveDirectoryReader, ActiveDirectoryReader>(); var activeDirectoryReader = Configuration.Get<ActiveDirectoryReader>(); activeDirectoryReader.ActiveDirectoryServerName = activeDirectoryServerName; } else { // Use fake AD search IocManager.Register<IActiveDirectoryReader, FakeActiveDirectoryReader>(); } #endregion Integration:ActiveDirectoryServer IocManager.Release(configurationAccessor); }
I shortened the name fot the file (EntityFrameworkCoreModule), the file is named GHREntityFrameworkCoreModule.cs so I guess it is the same file you mentioned.
-
0
I solved it. I had to add Depends on, but I added it the wrong way it seems,
I added it twice and this did not seem to work: [DependsOn(typeof(AbpAspNetCoreModule))] [DependsOn(typeof(GHREntityFrameworkCoreModule))]
Working way: [DependsOn(typeof(AbpAspNetCoreModule), typeof(GHREntityFrameworkCoreModule))]
It still caused an error but the site is now working so I guess the mentioned index does not pose an error:
[INFO ] 2019-03-06 16:05:54,165 [1 ] meworkCore.GHRMultiTenantMigrateExecuter - HOST database migration started... [ERROR] 2019-03-06 16:05:55,837 [1 ] meworkCore.GHRMultiTenantMigrateExecuter - Canceled migrations - An error occured during migration of host database. System.Data.SqlClient.SqlException (0x80131904): Cannot release index AppSubscriptionPayments.IX_AppSubscriptionPayments_PaymentId_Gateway, because the object does not exist or you do not have necessary rights. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource
1 completion, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite, String methodName) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary2 parameterValues) at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary
2 parameterValues) at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable1 migrationCommands, IRelationalConnection connection) at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration) at Abp.Zero.EntityFrameworkCore.AbpZeroDbMigrator
1.CreateOrMigrate(AbpTenantBase tenant, Action`1 seedAction) at EntityFrameworkCore.GHRMultiTenantMigrateExecuter.Run() ClientConnectionId:044c12ef-ea29-4054-ba90-a7d5839fa7c1 Error Number:3701,State:7,Class:11 -
0
It seems that the you are trying to store
LdapSettingNames.IsEnabled
for each tenant and load it during module initialization.This approach is incorrect as module initialization shouldn't have tenan/user concept. The more appropriate way is to get it from configuraiton.
configurationAccessor.Configuration["Integration:IsActiveDirectoryEnabled"];
-
0
What I'm actually trying to do is to check if LDAP is enabled for the system (not tenant, it is not a multi tenant system). If it is we will use the "real" AD Search. If not (i.e. on a development machine) we use a fake AD Search.
Is there a better way to check if the LDAP Setting has been enabled (as it is set/enabled in GUI)?
-
0
You can inject
IAbpZeroLdapModuleConfig
(for system) orILdapSettings
(for tenant) to determind if LDAP is enabled.ANZ uses ABP framework's AbpZeroLdapModule to implement LDAP authentication.
See ANZ implemenation at https://github.com/aspnetzero/aspnet-zero-core/blob/dev/aspnet-core/src/MyCompanyName.AbpZeroTemplate.Core/Authorization/Ldap/AppLdapAuthenticationSource.cs