Base solution for your next web application

Activities of "peabaw"

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?

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?

Hi

We have encountered a problem where PK int ID of an entity suddenly moves +1000 steps. Example: 1 2 3 1003 1004 2004 2005

This seems to be an issue related to the way Sql Server handles Identity column on a restart/reload: Consecutive values after server restart or other failures - SQL Server might cache identity values for performance reasons and some of the assigned values can be lost during a database failure or server restart. This can result in gaps in the identity value upon insert. If gaps are not acceptable then the application should use its own mechanism to generate key values. Using a sequence generator with the NOCACHE option can limit the gaps to transactions that are never committed. https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property?view=sql-server-2017

Normally, this is not an issue. Our customer, however, needs a sequence that moves along in a more linear matter.

How would you do it? T-Sql Sequence, EF Sequence (or other magic) or any other solution (the ABP/Zero way)?

Hello there

The LanguageAppService gives us a possibility to edit a language text:

public async Task UpdateLanguageText(UpdateLanguageTextInput input)

But why is there no Create?

public async Task CreateLanguageText(CreateLanguageTextInput input)

I guess there is a very good reason for that that I missed, so please hit me in the head with that explenation!

I'm asking because we need to dynamically create translatable language texts from the GUI to be used in the application. We are creating forms with 1..N inputs with labels, and these labels must be translatable. I thought I would be able to use the language DB in Zero and just create then through API but am I right that I need to implement a separate DB for this?

Solution: Asp.Net Zero angular+webapi

Hi

I have created a separate VS Project called Integrations. In this I have created a Module:

public class GHRIntegrationModule : AbpModule
    {
        public override void PreInitialize()
        {
            var configurationAccessor = IocManager.Resolve<IAppConfigurationAccessor>();
            var connectionString = configurationAccessor.Configuration["ConnectionStrings:ProjectSearch"];

            if (string.IsNullOrEmpty(connectionString))
            {
                //Use fake project search if database connection string is empty
                IocManager.Register<IProjectDataProvider, FakeProjectDataProvider>(DependencyLifeStyle.Singleton);
            }
            else
            {
                IocManager.Register<IProjectDataProvider, ProjectDataProvider>(DependencyLifeStyle.Singleton);
                var projectDataProvider = Configuration.Get<ProjectDataProvider>();
                projectDataProvider.DbConnectionString = connectionString;
            }
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(GHRIntegrationModule).GetAssembly());
        }
    }

The project currently contains a single AppService:

[AbpAuthorize]
    public class ProjectAppService : IProjectAppService
    {
        private readonly IProjectDataProvider _projectDataProvider;

        public ProjectAppService(IProjectDataProvider projectDataProvider)
        {
            _projectDataProvider = projectDataProvider;
        }

        [AbpAuthorize]
        public async Task<ProjectDto> GetProject(GetProjectInput input)
        {
            return await _projectDataProvider.GetProject(input);
        }

        [AbpAuthorize]
        public async Task<List<ProjectDto>> SearchProjects(SearchProjectInput input)
        {
            return await _projectDataProvider.SearchProjects(input);
        }
    }

I thought that the AppService would be picked up by the auto API controller creator and included in the API but it does not show up in Swagger for example so something is missing.

I have tried to add a call to create the controller for the app service but no change. I tried to add the following to the WebCoreModule PreInitialize and my own module's PreInitialize:

Configuration.Modules.AbpAspNetCore()
                .CreateControllersForAppServices(
                    typeof(GHRIntegrationModule).GetAssembly()
                );

I think I am only missing something easy and obvious.

Any tips wpuld be very appreciated!

Hello there

I have some problems getting Windows AND anonymous authentication to work. The login process is supposed to be like this:

  1. The user go to the angular site login. It should start an automatic AD/LDAP login process (as described at https://support.aspnetzero.com/QA/Questions/5370).
  2. If successful AD login, the user gets in.
  3. If unsuccessful, the user should return to the login page and be able to login using username and password as normal.

I have gotten some of this to work but when both Anonymous and Windows autentication is active in IIS, the User.Identity.IsAuthenticated is always false making LDAP login always unsuccessful.

I have changed the API web.config attribute forwardWindowsAuthToken="true".

I'm quite new to both IIS with .Net Core and especially Angluar, so any tips would be greatly appreciated!

Best regards // Andreas

Hi

I just activated LDAP through the GUI User Management and tried to log in with an AD user. It failed with internal error. The AD user does not have an email address and it seems this is a requirement currently in ABP/Zero, or am I wrong? How could I work around this to allow non-email AD users to login?

Service: TokenAuthController Action: Authenticate

Error state

System.NullReferenceException: Object reference not set to an instance of an object. at Abp.Authorization.Users.AbpUser1.SetNormalizedNames() at Abp.Authorization.AbpLogInManager3.TryLoginFromExternalAuthenticationSources(String userNameOrEmailAddress, String plainPassword, TTenant tenant) at Abp.Authorization.AbpLogInManager3.LoginAsyncInternal(String userNameOrEmailAddress, String plainPassword, String tenancyName, Boolean shouldLockout) at Abp.Authorization.AbpLogInManager3.LoginAsync(String userNameOrEmailAddress, String plainPassword, String tenancyName, Boolean shouldLockout) at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task1 actualReturnValue, Func1 postAction, Action`1 finalAction) at TokenAuthController.GetLoginResultAsync(String usernameOrEmailAddress, String password, String tenancyName) in .Web.Core\Controllers\TokenAuthController.cs:line 521 at Peab.GHR.Web.Controllers.TokenAuthController.Authenticate(AuthenticateModel model) in .Web.Core\Controllers\TokenAuthController.cs:line 107 at lambda_method(Closure , Object ) at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()

Best regards // Andreas

Showing 1 to 7 of 7 entries