Activities of "AlderCove"

Hi

Those fixes appear to have resolved the issues.

Thanks

Hi

It seems to work intermittently now.

After I log in the initial results are:

"auth": { "grantedPolicies": {} },

Sometimes, after I press F5, the granted policies are returned.

J

Yes - if I comment out that one depends on and the URL Shortening, then it works: "auth": { "grantedPolicies": { "FeatureManagement.ManageHostFeatures": true, "SettingManagement.Emailing": true, "SettingManagement.Emailing.Test": true, "SettingManagement.TimeZone": true, "AbpIdentity.Roles": true, "AbpIdentity.Roles.Create": true, "AbpIdentity.Roles.Update": true, "AbpIdentity.Roles.Delete": true, "AbpIdentity.Roles.ManagePermissions": true, "AbpIdentity.Users": true, "AbpIdentity.Users.Create": true, "AbpIdentity.Users.Update": true, "AbpIdentity.Users.Update.ManageRoles": true, "AbpIdentity.Users.Update.ManageOU": true, "AbpIdentity.Users.Delete": true, "AbpIdentity.Users.ManagePermissions": true, "AbpIdentity.Users.Impersonation": true, "AbpIdentity.Users.Import": true, "AbpIdentity.Users.Export": true, "AbpIdentity.Users.ViewDetails": true, "AbpIdentity.OrganizationUnits": true, "AbpIdentity.OrganizationUnits.ManageOU": true, "AbpIdentity.OrganizationUnits.ManageRoles": true, "AbpIdentity.OrganizationUnits.ManageMembers": true, "AbpIdentity.ClaimTypes": true, "AbpIdentity.ClaimTypes.Create": true, "AbpIdentity.ClaimTypes.Update": true, "AbpIdentity.ClaimTypes.Delete": true, "AbpIdentity.SettingManagement": true, "AbpIdentity.SecurityLogs": true, "AbpIdentity.Sessions": true, "AbpAccount.SettingManagement": true, "AuditLogging.AuditLogs": true, "AuditLogging.AuditLogs.Export": true, "OpenIddictPro.Application": true, "OpenIddictPro.Application.Update": true, "OpenIddictPro.Application.Delete": true, "OpenIddictPro.Application.Create": true, "OpenIddictPro.Application.ManagePermissions": true, "AuditLogging.ViewChangeHistory:Volo.Abp.OpenIddict.Pro.Applications.Application": true, "OpenIddictPro.Scope": true, "OpenIddictPro.Scope.Update": true, "OpenIddictPro.Scope.Delete": true, "OpenIddictPro.Scope.Create": true, "AuditLogging.ViewChangeHistory:Volo.Abp.OpenIddict.Pro.Scopes.Scope": true, "TextTemplateManagement.TextTemplates": true, "TextTemplateManagement.TextTemplates.EditContents": true, "LanguageManagement.LanguageTexts": true, "LanguageManagement.LanguageTexts.Edit": true, "LanguageManagement.Languages": true, "LanguageManagement.Languages.Create": true, "LanguageManagement.Languages.Edit": true, "LanguageManagement.Languages.ChangeDefault": true, "LanguageManagement.Languages.Delete": true, "FileManagement.DirectoryDescriptor": true, "FileManagement.DirectoryDescriptor.Create": true, "FileManagement.DirectoryDescriptor.Update": true, "FileManagement.DirectoryDescriptor.Delete": true, "FileManagement.FileDescriptor": true, "FileManagement.FileDescriptor.Create": true, "FileManagement.FileDescriptor.Update": true, "FileManagement.FileDescriptor.Delete": true, "FileManagement.FileDescriptor.Share": true, "CmsKitPublic.Comments": true, "CmsKitPublic.Comments.DeleteAll": true, "CmsKit.Comments": true, "CmsKit.Comments.Delete": true, "CmsKit.Comments.Update": true, "CmsKit.Comments.SettingManagement": true, "CmsKit.Tags": true, "CmsKit.Tags.Create": true, "CmsKit.Tags.Update": true, "CmsKit.Tags.Delete": true, "CmsKit.Pages": true, "CmsKit.Pages.Create": true, "CmsKit.Pages.Update": true, "CmsKit.Pages.Delete": true, "CmsKit.Pages.SetAsHomePage": true, "CmsKit.Blogs": true, "CmsKit.Blogs.Create": true, "CmsKit.Blogs.Update": true, "CmsKit.Blogs.Delete": true, "CmsKit.Blogs.Features": true, "CmsKit.BlogPosts": true, "CmsKit.BlogPosts.Create": true, "CmsKit.BlogPosts.Update": true, "CmsKit.BlogPosts.Delete": true, "CmsKit.BlogPosts.Publish": true, "CmsKit.Menus": true, "CmsKit.Menus.Create": true, "CmsKit.Menus.Update": true, "CmsKit.Menus.Delete": true, "CmsKit.GlobalResources": true, "CmsKit.Newsletter": true, "CmsKit.Newsletter.EditPreferences": true, "CmsKit.Newsletter.Import": true, "CmsKit.Poll": true, "CmsKit.Poll.Create": true, "CmsKit.Poll.Update": true, "CmsKit.Poll.Delete": true, "CmsKit.SettingManagement": true, "CmsKit.UrlShorting": true, "CmsKit.UrlShorting.Create": true, "CmsKit.UrlShorting.Update": true, "CmsKit.UrlShorting.Delete": true, "CmsKit.PageFeedback": true, "CmsKit.PageFeedback.Update": true, "CmsKit.PageFeedback.Delete": true, "CmsKit.PageFeedback.Settings": true, "CmsKit.PageFeedback.SettingManagement": true, "CmsKit.PageFeedback.Export": true, "CmsKit.Faq": true, "CmsKit.Faq.Create": true, "CmsKit.Faq.Update": true, "CmsKit.Faq.Delete": true, "Portal.Dashboard.Host": true }

Hi

I tried the suggested change in both the boilerplate generated solution, and my own production solution and it didn't make any difference.

Calls to the web project https://localhost:44376/Abp/ApplicationConfigurationScript still return: "auth": { "grantedPolicies": {} },

Here is my PortalWebPublicModule.cs :

using System; using System.IO; using Medallion.Threading; using Medallion.Threading.Redis; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Acs.Cts.Portal.Localization; using Acs.Cts.Portal.MultiTenancy; using Acs.Cts.Portal.Web.Public.Menus; using Acs.Cts.Portal.Web.Public.HealthChecks; using StackExchange.Redis; using Volo.Abp; using Volo.Abp.Studio; using Volo.Abp.AspNetCore.Authentication.OpenIdConnect; using Volo.Abp.AspNetCore.Mvc.Client; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.UI; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling; using Volo.Abp.LeptonX.Shared; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Mapperly; using Volo.Abp.BackgroundJobs; using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.DistributedLocking; using Volo.Abp.Http.Client.IdentityModel.Web; using Volo.Abp.Http.Client.Web; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; using Volo.Abp.UI; using Volo.Abp.UI.Navigation; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using Owl.reCAPTCHA; using Volo.Abp.GlobalFeatures; using Volo.CmsKit.GlobalFeatures; using Volo.CmsKit.Pro.Public.Web; using Volo.CmsKit.Pro.Public.Web.Middlewares; using Volo.CmsKit.Comments; using Volo.Abp.Studio.Client.AspNetCore; using System.Collections.Generic; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; using Volo.Abp.AspNetCore.Mvc.MultiTenancy; using Pages.Abp.MultiTenancy.ClientProxies;

namespace Acs.Cts.Portal.Web.Public;

[DependsOn( typeof(AbpAutofacModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpDistributedLockingModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpStudioClientAspNetCoreModule), typeof(AbpAspNetCoreMvcUiLeptonXThemeModule), typeof(PortalHttpApiClientModule), typeof(CmsKitProPublicWebModule), typeof(PortalHttpApiModule), typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule), typeof(AbpAspNetCoreMvcClientModule), typeof(AbpHttpClientWebModule), typeof(AbpHttpClientIdentityModelWebModule) )] public class PortalWebPublicModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => { options.AddAssemblyResource( typeof(PortalResource), typeof(PortalDomainSharedModule).Assembly, typeof(PortalApplicationContractsModule).Assembly, typeof(PortalWebPublicModule).Assembly ); }); }

public override void ConfigureServices(ServiceConfigurationContext context)
{
    var hostingEnvironment = context.Services.GetHostingEnvironment();
    var configuration = context.Services.GetConfiguration();

    if (!configuration.GetValue&lt;bool&gt;("App:DisablePII"))
    {
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
        Microsoft.IdentityModel.Logging.IdentityModelEventSource.LogCompleteSecurityArtifact = true;
    }

    ConfigureStudio(hostingEnvironment);
    ConfigureBundles();
    ConfigureUrls(configuration);
    ConfigureCache(configuration);
    ConfigureDataProtection(context, configuration, hostingEnvironment);
    ConfigureDistributedLocking(context, configuration);
    ConfigureMultiTenancy();
    ConfigureAuthentication(context, configuration);
    ConfigureVirtualFileSystem(hostingEnvironment);
    ConfigureNavigationServices(configuration);
    ConfigureTheme();
    ConfigureBackgroundJobs();
    ConfigureHealthChecks(context);

    context.Services.AddreCAPTCHAV3(o =>
    {
        o.SiteKey = "test";
        o.SiteSecret = "test";
    });

    Configure&lt;CmsKitCommentOptions&gt;(options =>
    {
        options.EntityTypes.Add(new CommentEntityTypeDefinition("SampleArticle"));
    });

    context.Services.RemoveAll(x =>
        x.ServiceType == typeof(IAbpApplicationConfigurationAppService) &&
        x.ImplementationType == typeof(AbpApplicationConfigurationClientProxy));

    context.Services.RemoveAll(x =>
        x.ServiceType == typeof(IAbpTenantAppService) &&
        x.ImplementationType == typeof(AbpTenantClientProxy));
}

private void ConfigureStudio(IHostEnvironment hostingEnvironment)
{
    if (hostingEnvironment.IsProduction())
    {
        Configure&lt;AbpStudioClientOptions&gt;(options =>
        {
            options.IsLinkEnabled = false;
        });
    }
}

private void ConfigureBundles()
{
    Configure&lt;AbpBundlingOptions&gt;(options =>
    {
        options.StyleBundles.Configure(
            LeptonXThemeBundles.Styles.Global,
            bundle =>
            {
                bundle.AddFiles("/global-styles.css");
            }
        );

        options.ScriptBundles.Configure(
            LeptonXThemeBundles.Scripts.Global,
            bundle =>
            {
                bundle.AddFiles("/global-scripts.js");
            }
        );
    });
}

private void ConfigureBackgroundJobs()
{
    Configure&lt;AbpBackgroundJobOptions&gt;(options =>
    {
        options.IsJobExecutionEnabled = false;
    });
}

private void ConfigureTheme()
{
    Configure&lt;LeptonXThemeOptions&gt;(options =>
    {
        options.DefaultStyle = LeptonXStyleNames.System;
    });

    Configure&lt;LeptonXThemeMvcOptions&gt;(options =>
    {
        options.ApplicationLayout = LeptonXMvcLayouts.PublicWebsite;
    });
}

private void ConfigureHealthChecks(ServiceConfigurationContext context)
{
    context.Services.AddPortalPublicHealthChecks();
}

private void ConfigureUrls(IConfiguration configuration)
{
    Configure&lt;AppUrlOptions&gt;(options =>
    {
        options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
    });
}

private void ConfigureCache(IConfiguration configuration)
{
    Configure&lt;AbpDistributedCacheOptions&gt;(options =>
    {
        options.KeyPrefix = "Portal:";
    });
}

private void ConfigureMultiTenancy()
{
    Configure&lt;AbpMultiTenancyOptions&gt;(options => { options.IsEnabled = MultiTenancyConsts.IsEnabled; });
}

private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
    context.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("Cookies", options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromDays(365);
        options.CheckTokenExpiration();
    })
    .AddAbpOpenIdConnect("oidc", options =>
    {
        options.Authority = configuration["AuthServer:Authority"];
        options.RequireHttpsMetadata = configuration.GetValue&lt;bool&gt;("AuthServer:RequireHttpsMetadata");
        options.ResponseType = OpenIdConnectResponseType.CodeIdToken;

        options.ClientId = configuration["AuthServer:ClientId"];
        options.ClientSecret = configuration["AuthServer:ClientSecret"];

        options.SaveTokens = true;
        options.GetClaimsFromUserInfoEndpoint = true;

        options.Scope.Add("roles");
        options.Scope.Add("email");
        options.Scope.Add("phone");
        options.Scope.Add("Portal");
        options.Scope.Add("CmsKit");
        options.Scope.Add("CmsKitPublic");
    });
    /*
    * This configuration is used when the AuthServer is running on the internal network such as docker or k8s.
    * Configuring the redirectin URLs for internal network and the web
    */
    if (configuration.GetValue&lt;bool&gt;("AuthServer:IsOnK8s"))
    {
        context.Services.Configure&lt;OpenIdConnectOptions&gt;("oidc", options =>
        {
            options.TokenValidationParameters.ValidIssuers = new[] {
                configuration["AuthServer:MetaAddress"]!.EnsureEndsWith('/'),
                configuration["AuthServer:Authority"]!.EnsureEndsWith('/')
            };

            options.MetadataAddress = configuration["AuthServer:MetaAddress"]!.EnsureEndsWith('/') +
                                        ".well-known/openid-configuration";

            var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider;
            options.Events.OnRedirectToIdentityProvider = async ctx =>
            {
                // Intercept the redirection so the browser navigates to the right URL in your host
                ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') + "connect/authorize";

                if (previousOnRedirectToIdentityProvider != null)
                {
                    await previousOnRedirectToIdentityProvider(ctx);
                }
            };
            var previousOnRedirectToIdentityProviderForSignOut =
                options.Events.OnRedirectToIdentityProviderForSignOut;
            options.Events.OnRedirectToIdentityProviderForSignOut = async ctx =>
            {
                // Intercept the redirection for signout so the browser navigates to the right URL in your host
                ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') + "connect/endsession";

                if (previousOnRedirectToIdentityProviderForSignOut != null)
                {
                    await previousOnRedirectToIdentityProviderForSignOut(ctx);
                }
            };
        });
    }

    context.Services.Configure&lt;AbpClaimsPrincipalFactoryOptions&gt;(options =>
    {
        options.IsDynamicClaimsEnabled = true;
    });
}

private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
{
    Configure&lt;AbpVirtualFileSystemOptions&gt;(options =>
    {
        options.FileSets.AddEmbedded&lt;PortalWebPublicModule&gt;();

        if (hostingEnvironment.IsDevelopment())
        {
            options.FileSets.ReplaceEmbeddedByPhysical&lt;PortalDomainSharedModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Acs.Cts.Portal.Domain.Shared", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;PortalApplicationContractsModule&gt;(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}Acs.Cts.Portal.Application.Contracts", Path.DirectorySeparatorChar)));
            options.FileSets.ReplaceEmbeddedByPhysical&lt;PortalWebPublicModule&gt;(hostingEnvironment.ContentRootPath);
        }
    });
}

private void ConfigureNavigationServices(IConfiguration configuration)
{
    Configure&lt;AbpNavigationOptions&gt;(options =>
    {
        options.MenuContributors.Add(new PortalPublicMenuContributor(configuration));
    });

    Configure&lt;AbpToolbarOptions&gt;(options =>
    {
        options.Contributors.Add(new PortalToolbarContributor());
    });
}

private void ConfigureDataProtection(
    ServiceConfigurationContext context,
    IConfiguration configuration,
    IWebHostEnvironment hostingEnvironment)
{
    if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
    {
        return;
    }

    var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("Portal");
    if (!hostingEnvironment.IsDevelopment())
    {
        var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
        dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "Portal-Protection-Keys");
    }
}

private void ConfigureDistributedLocking(
    ServiceConfigurationContext context,
    IConfiguration configuration)
{
    if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
    {
        return;
    }

    context.Services.AddSingleton&lt;IDistributedLockProvider&gt;(sp =>
    {
        var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
        return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
    });
}

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();
    var env = context.GetEnvironment();

    if (GlobalFeatureManager.Instance.IsEnabled&lt;UrlShortingFeature&gt;())
    {
        app.UseMiddleware&lt;UrlShortingMiddleware&gt;();
    }
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAbpRequestLocalization();

    if (!env.IsDevelopment())
    {
        app.UseErrorPage();
    }

    app.UseRouting();
    app.MapAbpStaticAssets();
    app.UseAbpStudioLink();
    app.UseAbpSecurityHeaders();
    app.UseAuthentication();

    if (MultiTenancyConsts.IsEnabled)
    {
        app.UseMultiTenancy();
    }

    app.UseDynamicClaims();
    app.UseAuthorization();
    app.UseAbpSerilogEnrichers();
    app.UseConfiguredEndpoints();
}

}

Summary Description In a freshly generated ABP v10.1.0 Tiered solution (Studio 2.2.1), there is a critical failure in permission resolution for the Web.Public (MVC/Razor) application when the CmsKit module is included. While the Angular UI functions correctly, the Web.Public app receives an empty grantedPolicies object in the Abp/ApplicationConfigurationScript response, effectively breaking all authorized UI elements.

Troubleshooting has revealed a "chained" failure in the template generation:

The OpenIddict Data Seeder fails to create the required CmsKit and CmsKitPublic scopes.

Even after manually patching the scopes and ensuring a successful OIDC handshake, the Permission/Feature Checkers on the Host/Public-Web boundary fail to populate the policies.

Additionally, a UI bug in ABP Studio incorrectly displays the --without-cms-kit flag in the solution configuration even when the module is present.

Check the docs before asking a question: https://abp.io/docs/latest - Checked. Check the samples to see the basic tasks: https://abp.io/docs/latest/samples - Checked. Search on the homepage: Checked. (Ref: Similar issues found in 10.x regarding empty grantedPolicies).

Solution Configurations Configuration 1: WORKING Solution (No CmsKit)

Template: app

Created ABP Studio Version: 2.2.1

Current ABP Studio Version: 2.2.1

Tiered: Yes

Multi-Tenancy: No

UI Framework: angular

Database Provider: ef

Database Management System: sqlserver

Public Website: Yes

Create Command: abp new Acs.Cts.Portal -t app --tiered --ui-framework angular --database-provider ef --database-management-system sqlserver --theme leptonx --skip-migration --skip-migrator --no-tests --public-website --without-cms-kit --dont-run-install-libs --dont-run-bundling --no-multi-tenancy --no-social-logins -file-management

Configuration 2: NON-WORKING Solution (Includes CmsKit)

Template: app

Created ABP Studio Version: 2.2.1

Current ABP Studio Version: 2.2.1

Tiered: Yes

Multi-Tenancy: No

UI Framework: angular

Database Provider: ef

Database Management System: sqlserver

Public Website: Yes

Optional Modules: CmsKit (Selected in UI)

Create Command (Observed Bug): abp new Acs.Cts.Portal -t app --tiered --ui-framework angular --database-provider ef --database-management-system sqlserver --theme leptonx --skip-migration --skip-migrator --no-tests --public-website --without-cms-kit --dont-run-install-libs --dont-run-bundling --no-multi-tenancy --no-social-logins -file-management

Note: Even though CmsKit was selected and packages are physically referenced in the solution, the Studio configuration window incorrectly displays --without-cms-kit.

Exception message and full stack trace Issue: The Web.Public (MVC/Razor) application fails to retrieve permissions for authenticated users when CmsKit is installed. The response from Abp/ApplicationConfigurationScript shows: "auth": { "grantedPolicies": {} }

Technical Findings during troubleshooting:

Missing Scopes: The v10.1 template/migrator failed to seed CmsKit and CmsKitPublic into the OpenIddictScopes table.

Invalid Scope Error: When manually adding these scopes to AbpOpenIdConnectOptions in the Web.Public module, OpenIddict returns error:invalid_scope (ID2052) because the scopes are missing from the database.

Persistent Empty Policies: After manually patching the OpenIddictDataSeedContributor to include these scopes and confirming the OIDC handshake succeeds with the correct scopes in the token, the grantedPolicies object remains empty.

Steps to reproduce the issue Create a brand new Tiered solution with Public Website using ABP Studio 2.2.1 (v10.1.0).

Select the CmsKit module during the creation process.

Run the migrations and start the AuthServer, HttpApi.Host, and Web.Public applications.

Log in as 'admin' on the Web.Public site.

Inspect the response of https://localhost:XXXX/Abp/ApplicationConfigurationScript.

Observe: The grantedPolicies object is empty { }.

Compare: Create an identical solution without CmsKit. Perform the same login.

Observe: grantedPolicies are correctly populated for the same 'admin' user.

Secondary Issues Observed ABP Studio Sync Bug: When creating a solution with CmsKit, the "Solution Configuration" window (and the generated CLI command) incorrectly lists the --without-cms-kit flag, even though the module is physically integrated into the solution.

Missing Data Seeding: The default DataSeeder for v10.1 tiered solutions appears to miss the required OpenIddict Scopes for CmsKit, preventing the Public Web client from successfully authorized communication with the API host out-of-the-box.

I removed project references made to <PackageReference Include="Volo.Abp.Identity.Pro.Application.Contracts" Version="10.0.1" /> <PackageReference Include="Volo.Abp.Identity.Pro.Domain" Version="10.0.1" /> from the corresponding DDD module project and removed reference made to IdentityUser and the issue no longer occurs

Docs checked:

https://abp.io/docs/latest

https://abp.io/docs/latest/samples

Searched ABP homepage & GitHub issues (including issue #9602 and related threads)

🧩 Problem Summary

I am getting the following EF Core runtime error when navigating to a page that queries a custom module entity:

The entity type ExtraPropertyDictionary requires a primary key to be defined. If you intended to use a keyless entity type, call HasNoKey in OnModelCreating.

This occurs during runtime DbContext model initialization (first repository access), not during migrations.

The entity in question inherits from FullAuditedAggregateRoot<Guid> and does not explicitly define or map ExtraPropertyDictionary.

🧪 Environment

ABP version: 10.0.1 (Commercial / Pro)

Created with: ABP Studio

Architecture:

Tiered solution

Modular (apps + modules folder structure)

Database: SQL Server

ORM: EF Core

Identity: ABP Identity / Identity Pro

Frontend: Angular

💥 Exception message and full stack trace The entity type 'ExtraPropertyDictionary' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.

System.InvalidOperationException: The entity type 'ExtraPropertyDictionary' requires a primary key to be defined. at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, ...) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(...) ... at Volo.Abp.EntityFrameworkCore.AbpDbContext1.Initialize(...) at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.GetDbSetAsync() at Acs.PrincipalGraph.Principals.EfCorePrincipalRepository.GetQueryForNavigationPropertiesAsync() at Acs.PrincipalGraph.Principals.PrincipalsAppService.GetListAsync(...)

🧬 Entity Definition public abstract class PrincipalBase : FullAuditedAggregateRoot<Guid>, IMultiTenant { public Guid? TenantId { get; set; }

public PrincipalKind Kind { get; set; }
public PrincipalScope Scope { get; set; }

public string? ExternalId { get; set; }
public string? DisplayName { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }

public bool IsActive { get; set; }

public Guid? UserId { get; set; }

}

ExtraProperties and ConcurrencyStamp are inherited from FullAuditedAggregateRoot

I did not define ExtraPropertyDictionary anywhere in my code

🗂 Module EF Core Mapping public static void ConfigurePrincipalGraph(this ModelBuilder builder) { builder.Entity<Principal>(b => { b.ToTable("AcsPrincipals"); b.ConfigureByConvention();

    b.Property(x => x.ExternalId).HasMaxLength(512);
    b.Property(x => x.DisplayName).HasMaxLength(128);
    b.Property(x => x.FirstName).HasMaxLength(128);
    b.Property(x => x.LastName).HasMaxLength(128);

    b.HasOne&lt;IdentityUser&gt;()
        .WithMany()
        .HasForeignKey(x => x.UserId)
        .OnDelete(DeleteBehavior.SetNull);
});

}

🧱 Runtime DbContext OnModelCreating protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder);

builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureFeatureManagement();
builder.ConfigureIdentityPro();
builder.ConfigureOpenIddictPro();
builder.ConfigureLanguageManagement();
builder.ConfigureSaas();
builder.ConfigureTextTemplateManagement();
builder.ConfigureGdpr();
builder.ConfigureCmsKit();
builder.ConfigureCmsKitPro();
builder.ConfigureBlobStoring();

builder.ConfigureFoundation();
builder.ConfigurePrincipalGraph();

}

🔁 Steps to Reproduce

Create a new ABP 10.0.1 solution using ABP Studio (tiered, modular).

Create a custom module.

Add an entity inheriting from FullAuditedAggregateRoot<Guid>.

Add EF Core mapping using ConfigureByConvention().

Reference IdentityUser with a FK (HasOne<IdentityUser>()).

Run the application.

Navigate to a page that queries the entity via an EF Core repository.

➡️ Runtime throws ExtraPropertyDictionary requires a primary key.

❓ What I’m Trying to Understand

Is this a missing or new required configuration in ABP 10.x for modular DbContexts?

Should ConfigureObjectExtensions() be required explicitly in runtime DbContexts?

Is there an ordering requirement between:

ConfigureObjectExtensions

ConfigureIdentity / ConfigureIdentityPro

custom module mappings?

Is there a recommended pattern when custom modules reference IdentityUser and use audited aggregate roots?

I expected FullAuditedAggregateRoot + ConfigureByConvention() to be sufficient, as in earlier ABP versions.

✅ What I’ve Already Tried

Removing the IdentityUser relationship (error still occurs)

Verifying no DbSet<ExtraPropertyDictionary> exists

Verifying no explicit modelBuilder.Entity<ExtraPropertyDictionary>()

Comparing with GitHub issue #9602 and similar threads

Added issue to backlog: https://github.com/abpframework/abp/issues/24077

It looks to me like I'd have to replace the whole navbar.

How can I add a request for the Lepton-X theme to be changed so that when its expanded the collapse icon is visible:

and when Its collapsed, the expand icon is visble:

Also making accessible as a button would be preferred.

thanks

I’ve reviewed the latest ABP documentation and samples, but couldn’t find guidance on extending LeptonX UI behavior for accessibility (keyboard interaction and ARIA support).

Context In the LeptonX UI layout, the left navigation menu includes a collapse icon (the small ) that narrows the sidebar to icon-only mode. When collapsed, it automatically expands again when hovered with the mouse.

However, this interaction currently depends entirely on mouse hover, which makes it inaccessible to keyboard and screen reader users. When the menu is collapsed, there’s no keyboard-focusable control available to re-expand it.

What I’m Trying to Achieve

I’d like to implement keyboard accessibility and ARIA support for the LeptonX sidebar collapse/expand toggle, in alignment with WCAG 2.1 AA requirements.

Specifically, the improvements should:

  • Make the collapse icon keyboard focusable ( or role="button").
  • Toggle the sidebar state on Enter/Space.
  • Expose the menu’s state via aria-expanded="true|false".
  • Keep a persistent, focusable toggle even when the sidebar is collapsed.
  • Optionally expand the sidebar when it gains keyboard focus (to match hover behavior).

Current HTML Structure <lpx-icon iconclass="bi bi-filter-left" class="menu-collapse-icon hidden-in-hover-trigger" ng-reflect-icon-class="bi bi-filter-left"> <i aria-hidden="true" class="lpx-icon bi bi-filter-left"></i> </lpx-icon>

Goal Example (Accessible Version) <button type="button" class="menu-collapse-icon" [attr.aria-label]="isCollapsed ? 'Expand navigation' : 'Collapse navigation'" [attr.aria-expanded]="!isCollapsed" (click)="toggleSidebar()"> Where toggleSidebar() updates the isCollapsed state and toggles a CSS class on the sidebar container.

Request for Assistance Could you please advise on:

  • The best practice or extension point in LeptonX layout to override or extend this behavior cleanly?
  • Whether there’s a recommended way to customize or replace the collapse icon template within the lpx-layout component.
  • If any ABP-provided directive/service already handles sidebar state so we can bind to it instead of reimplementing the logic.
  • Any considerations to maintain compatibility with LeptonX hover-trigger behavior while adding focus-trigger support.

Environment Info ABP Framework Version: 9.x UI Framework: Angular (LeptonX Theme) Solution Type: Modular Monolith (ABP Commercial) Browser: Chrome 141 Accessibility Tools Used: NVDA, Axe, and WAVE

Steps to Reproduce

Run the Angular application with LeptonX theme. Collapse the left navigation using the collapse icon. Attempt to re-expand using only the keyboard — there’s no focusable element. Observe: menu can only expand on mouse hover, not via keyboard.

Expected Result

Keyboard users should be able to toggle the sidebar state using Tab + Enter/Space, and assistive technologies should receive correct aria-expanded and label updates.

Showing 1 to 10 of 96 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.3.0-preview. Updated on March 13, 2026, 12:51
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.