Base solution for your next web application

Activities of "peabaw"

So I changed the side-bar-menu's init to this:

ngOnInit() {
        var res: Array<AppMenuItem> = [];
        this._formsServiceProxy.getFormsForMenu().forEach(element =>
            { 
                element.forEach(item => 
                    {
                        var subItems = [];
                        subItems.push(new AppMenuItem(this._appLocalizationService.l('Incidents'), 'Pages.Incidents', 'flaticon-more', '/app/main/registrations/incidents/' + item.form.area, [], false, {formArea: item.form.area}));
                        subItems.push(new AppMenuItem(this._appLocalizationService.l('CreateNewIncident') + ' ' + this._appLocalizationService.l(item.form.translationId), 'Pages.Incidents.Create', 'flaticon-add', '/app/main/registrations/incident/new/' + item.form.area, [], false, {form: item.form.id}))
                        res.push(new AppMenuItem(this._appLocalizationService.l(item.form.translationId), '', 'flaticon-more', '', subItems));
                    });
            }
        );
        
        this.menu = this._appNavigationService.getMenu(res);

        this.currentRouteUrl = this.router.url.split(/[?#]/)[0];

        this.router.events
            .pipe(filter(event => event instanceof NavigationEnd))
            .subscribe(event => this.currentRouteUrl = this.router.url.split(/[?#]/)[0]);
    }

app-navigation getMenu:

getMenu(dynamicMenuItems: Array<AppMenuItem>): AppMenu {
        // TODO: Api call to _formsServiceProxy.getFormsForMenu() loads too late, not visible in gui on initial loading /AW
        var res: Array<AppMenuItem> = [];
        res.push(new AppMenuItem('Dashboard', 'Pages.Administration.Host.Dashboard', 'flaticon-line-graph', '/app/admin/hostDashboard'),
            new AppMenuItem('Dashboard', 'Pages.Tenant.Dashboard', 'flaticon-line-graph', '/app/main/dashboard'),
            new AppMenuItem('Tenants', 'Pages.Tenants', 'flaticon-list-3', '/app/admin/tenants'),
            new AppMenuItem('Editions', 'Pages.Editions', 'flaticon-app', '/app/admin/editions')
        );
        
        dynamicMenuItems.forEach(element => res.push(element));

Now the menu items do not even show up, not even on mouse over. Also tried to execute the api-call in the constructor, but no change.

Did I miss something?

Second part is solved. First part is unfortunately still an issue.

Typical, you ask the question and then possibly solves it... I'll close this and reopen in case I does not work.

Hi there

Two questions regarding menu and routing in angular + api that I cannot seem to find a way around.

  1. Menu:

I am dynamically generating a menu depending on the "Forms" that are in the system. The problem is that the menu is rendered before the API-call is done, so no dynamic menu items shows up. That is until you mouse over the left meny, then they appers.

Do I need to load them earlier? Where? How? Or could I force it to wait for the API call to finish?

app-navigation.service.ts:

getMenu(): AppMenu {
        var res: Array<AppMenuItem> = [];
        res.push(new AppMenuItem('Dashboard', 'Pages.Administration.Host.Dashboard', 'flaticon-line-graph', '/app/admin/hostDashboard'),
            new AppMenuItem('Dashboard', 'Pages.Tenant.Dashboard', 'flaticon-line-graph', '/app/main/dashboard'),
            new AppMenuItem('Tenants', 'Pages.Tenants', 'flaticon-list-3', '/app/admin/tenants'),
            new AppMenuItem('Editions', 'Pages.Editions', 'flaticon-app', '/app/admin/editions')
        );
        
        this._formsServiceProxy.getFormsForMenu().forEach(element =>
            { 
                element.forEach(item => 
                    {
                        var subItems = [];
                        subItems.push(new AppMenuItem(this._appLocalizationService.l('Incidents'), 'Pages.Incidents', 'flaticon-more', '/app/main/registrations/incidents'));
                        subItems.push(new AppMenuItem(this._appLocalizationService.l('CreateNewIncident') + ' ' + this._appLocalizationService.l(item.form.translationId), 'Pages.Incidents.Create', 'flaticon-add', '/app/main/registrations/incident/new', [], false, {form: item.form.id}))
                        res.push(new AppMenuItem(this._appLocalizationService.l(item.form.translationId), '', 'flaticon-more', '', subItems));
                    });
            }
        );
                
        return new AppMenu('MainMenu', 'MainMenu', res);
    }
  1. Routing/Menu selected item

The dynamically generated menu items are a "parent" and two children. The first child is going to a list of already created form items (/app/main/registrations/incidents) and the other to the CreateNewFormItem (/app/main/registrations/incident/new). The listing and creation/editing are the same component regardless of Form.

Example:

Menu:

Form 1 List CreateNew Form 2 List CreateNew

The problem I have is that when you click "Form 1->List" BOTH "Form1->List" and "Form2->List" becomes menu selected (as they have the same routing url). I have tried to google angular routing and if there are any "placeholders/dummy" attributes to use but have not found anything.

imports: [
        RouterModule.forChild([
            {
                path: '',
                children: [
                    { path: 'registrations/incident/new', component: CreateOrEditIncidentComponent, data: { permission: 'Pages.Incidents' } },
                    { path: 'registrations/incident/edit/:incidentId', component: CreateOrEditIncidentComponent, data: { permission: 'Pages.Incidents' } },
                    { path: 'registrations/incidents', component: IncidentsComponent, data: { permission: 'Pages.Incidents' } },
                    { path: 'dashboard', component: DashboardComponent, data: { permission: 'Pages.Tenant.Dashboard' } }
                ]
            }
        ])
    ],

How can I make the url unique AND at the same time route the calls to the same path? Is it possible the routing way or is it someting for the menu to handle instead?

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)?

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, Action1 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(TaskCompletionSource1 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, IReadOnlyDictionary2 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.AbpZeroDbMigrator1.CreateOrMigrate(AbpTenantBase tenant, Action`1 seedAction) at EntityFrameworkCore.GHRMultiTenantMigrateExecuter.Run() ClientConnectionId:044c12ef-ea29-4054-ba90-a7d5839fa7c1 Error Number:3701,State:7,Class:11

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.

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.

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.&lt;&gt;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.&lt;Get&gt;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.&lt;&lt;GetAsync&gt;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 ---

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?

Showing 1 to 10 of 22 entries