Activities of "maliming"

Hi,

IdentitySessionCleanupService runs the delete once in the host context, so the multi-tenant filter limits it to TenantId IS NULL and tenant sessions are never removed. It should loop the tenants the same way ExpiredAuditLogDeleterService does. We'll fix this in 10.7, and your ticket credit has been refunded.

For now, override the service instead of adding another worker. The built-in worker resolves IdentitySessionCleanupService from DI, so it picks up the override and you keep the distributed lock and the IdentitySessionCleanupOptions settings:

using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Session;
using Volo.Abp.MultiTenancy;

namespace MyCompanyName.MyProjectName;

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IdentitySessionCleanupService))]
public class TenantAwareIdentitySessionCleanupService : IdentitySessionCleanupService
{
    protected ITenantStore TenantStore { get; }
    protected ICurrentTenant CurrentTenant { get; }
    protected IDataFilter DataFilter { get; }

    public TenantAwareIdentitySessionCleanupService(
        IOptionsMonitor<IdentitySessionCleanupOptions> cleanupOptions,
        IdentitySessionManager identitySessionManager,
        ITenantStore tenantStore,
        ICurrentTenant currentTenant,
        IDataFilter dataFilter)
        : base(cleanupOptions, identitySessionManager)
    {
        TenantStore = tenantStore;
        CurrentTenant = currentTenant;
        DataFilter = dataFilter;
    }

    public override async Task CleanAsync()
    {
        using (CurrentTenant.Change(null))
        using (DataFilter.Disable<IMultiTenant>())
        {
            await base.CleanAsync();
        }

        foreach (var tenant in await TenantStore.GetListAsync())
        {
            using (CurrentTenant.Change(tenant.Id))
            {
                await base.CleanAsync();
            }
        }
    }
}

Put it in your .Domain project and remove it when you upgrade to 10.7. The host pass runs with the multi-tenant filter disabled, so the tenant rows sitting in your host database are removed too, and the per-tenant pass covers the separate tenant databases.

Thanks

Hi,

Point 2 needs a correction — the deployed application does run a license check at startup.

It's a local check: the app validates the AbpLicenseCode from its own configuration, without contacting any ABP server and without needing abp login on that machine, so it works on an offline server too. But the code has to stay in your production configuration. If it's missing or invalid, you get ABP-LIC-ERROR in the logs and the app shuts down.

The one case where a deployed instance does call abp.io is when it runs with ASPNETCORE_ENVIRONMENT=Development or with a debugger attached. Keep it on Production and the online check never runs. These two cover it in detail:

https://abp.io/support/questions/817/How-to-delete-current-license-login-session https://abp.io/support/questions/1471/containerizing-abp-application

For your other two questions:

License not renewed: your deployed applications are not affected, they keep running. You can also keep developing your existing projects — ABP licenses are perpetual. What ends is creating new solutions from the pro templates, major/minor upgrades (you still get the patches of your current minor version), installing new pro modules and themes, ABP Suite, ABP Studio's pro features, and premium support. The full list is under "What happens when my license period ends?" on https://abp.io/faq

Downgrade: license plans can't be downgraded. If you need to change your plan, write to info@abp.io

Project count and deployments are both unlimited, and the license is tied to developer seats, not to the number of projects or deployments. One detail on the first point: you can create as many projects as you want while the license is active, and after it expires you can't create new ones, but everything you already have keeps working and can be deployed anywhere.

Thanks

Hi,

NG6008 isn't an Angular 22 compiler bug. Since Angular 19 the standalone flag defaults to true, so a component declared in an NgModule now needs an explicit standalone: false. That's why all 639 of them fail at once. Editing the versions in package.json and running npm install skips the ng update migrations that would have added the flag, along with everything else five major versions changed.

So the upgrade is doable, and it's worth doing. An 8.3 Angular frontend against a 10.6 backend isn't a pairing we ship or test, the Angular packages are released together with the backend ones, so it isn't something to settle on.

Start over from your Angular 17.3 branch and repeat the same hop for Angular 18, 19, 20, 21 and 22:

  1. Set your Angular-coupled third-party libraries to the version built for the major you're moving to, then npm install --legacy-peer-deps. ng update refuses to start while an installed library declares an incompatible peer, and @ngxs/store@3.8.2 (Angular <18) and @ng-select/ng-select@11.2.0 (Angular ^16) already stop it on the first hop. Take the number from each library's own compatibility list instead of assuming it follows the Angular major. NGXS, ng-zorro and angularx-qrcode do line up with it, ng-select doesn't: 13.9.1, 14.9.0, 20.7.0, 21.8.2, 24.0.4 for Angular 18 through 22.

  2. Run the update with Material and the CDK in the same command:

ng update @angular/core@18.1 @angular/cli@18.1 @angular/material@18 @angular/cdk@18

Keep the ~ ranges you already have and pass major.minor for core and the CLI. That's what keeps you on the minor ABP targets instead of jumping to the newest one.

  1. Set the @abp/* and @volo/* packages to the matching ABP version. From ABP 10.2 on you also need @angular/aria as a direct dependency, on the same version as Angular.

| Angular | ABP | |---|---| | ~18.1 | 9.0 | | ~19.1 | 9.1 | | ~20.0 | 9.3 | | ~21.0 | 10.1 | | ~22.0 | 10.6 |

  1. Delete node_modules and the lock file, reinstall, build and run the app. Then start the next hop.

Node 23 isn't supported by any Angular version in this chain. Node 20.19+ carries you through the Angular 21 hop, then switch to Node 22.22.3+ or 24.15+ for the last one.

Go through the ABP migration guide of every version you cross, not only the last one. Two that are easy to miss in a module-based app: provideZoneChangeDetection() in AppModule.providers (10.1), and regenerating the Angular proxies with abp generate-proxy -t ng against the upgraded backend (10.6), since upload proxies changed.

https://abp.io/docs/latest/release-info/migration-guides/abp-10-6-angular-22

Three things from your report that the hops won't sort out by themselves:

  • The v19 and v22 migrations rewrite the decorator of every component, adding standalone: false and ChangeDetectionStrategy.Eager. The changes are mechanical and your component logic stays as it is, but if a zero .ts diff is an absolute rule then this upgrade can't be done at all.
  • Keep useDefineForClassFields: false in tsconfig.json. That's where the 13 TS2729 errors come from, and the TS2612 ones as well, so the declare keywords you added for those can come back out.
  • ABP 10.6 needs @ng-bootstrap/ng-bootstrap on ~20.0.0, which the theme package brings in. Don't pin it yourself, the 18.0.0 in your build doesn't export the ./tooltip entry point and that's where the resolve error comes from. That version is still declared against the previous Angular major, so install with --legacy-peer-deps.

Thanks

Hi,

Nothing in ABP reads or writes that column outside the value converter, so the store type is yours to pick.

On the EF Core side, the only things configured for ExtraProperties are the column name, the converter and a value comparer (TryConfigureExtraProperties). There is no HasColumnType, no HasMaxLength and no default value — nvarchar(max) is what the provider picks for a converted string, not something the framework asks for.

For the four areas you listed:

  • ObjectExtensionManager: MapEfCoreProperty adds a separate real column. Its only contact with the bag is in the converter, which strips mapped keys before serializing, and in AbpDbContext.FillExtraPropertiesForTrackedEntities / HandleExtraPropertiesOnSave, which copy values between the dictionary and that column. All on the CLR side.
  • Audit log property changes: EntityHistoryHelper reads propertyEntry.CurrentValue / OriginalValue, which are ExtraPropertyDictionary instances, and serializes them in C#. It never sees the provider value. It records the bag as one property change rather than per key, and truncates to 512 chars, but that is already the case on nvarchar.
  • Distributed events: nothing reads that column. The default EntityEto doesn't carry the entity's extra properties at all, and the ETOs that do expose them take them from the CLR dictionary. The outbox and inbox tables keep EventData as byte[].
  • MongoDB: ExtraProperties is mapped as the BSON extra-elements member, so the keys become top-level document fields. Different provider, different mapping, unaffected either way.

ABP 10.6 also doesn't filter, sort or search the contents of that column in any of its built-in EF Core queries.

For the override itself, go through ObjectExtensionManager rather than a single DbContext:

ObjectExtensionManager.Instance
    .MapEfCoreEntity<IdentityUser>(b =>
    {
        b.Property(nameof(IHasExtraProperties.ExtraProperties)).HasColumnType("jsonb"); // json on SQL Server
    });

That goes in your <YourProject>EfCoreEntityExtensionMappings.Configure(). The reason to prefer it: it lands in whichever DbContext maps the entity, including a module's own one at runtime. If you configure it only on your application DbContext, it covers your own entities and the modules you replace with [ReplaceDbContext] (the template does that for Identity and Saas), but a module you don't replace keeps its own model, and you end up with a converted column against a model that still says string — writes then fail with a type mismatch.

Two more things to plan for:

  • Back up the database first, and try the whole thing on a copy before you touch the real tables. This rewrites a column in place on tables you can't afford to lose. Review the generated migration too, don't just apply it — it comes out as a plain AlterColumn, and every existing value has to be a JSON object or SQL NULL, not just valid JSON. An empty string fails the conversion, while an array or a string/number literal passes it and then throws on read, since the converter deserializes into a dictionary. On PostgreSQL the bare AlterColumn is rejected outright and you write the cast yourself: ALTER TABLE "AbpUsers" ALTER COLUMN "ExtraProperties" TYPE jsonb USING "ExtraProperties"::jsonb.
  • Changing the store type doesn't change how EF Core sees the column. It's still one converted string property, so x.ExtraProperties[...] stays untranslatable in LINQ.

On the roadmap question: the tracked item is https://github.com/abpframework/abp/issues/23546, making ExtraProperties queryable at the database level. It's open and in the backlog, with no target release. The approach it explores is EF Core's owned-JSON mapping (OwnsOne(...).ToJson()), which needs every key declared up front — unconfigured keys can't be written or ordered by, which is why it stalled on exactly the requirement you care about. It doesn't cover switching the store type on its own.

One last thing, since you are on SQL Server 2025 on-premises rather than Azure SQL: the native json type and CREATE JSON INDEX are both still in preview there — https://learn.microsoft.com/sql/relational-databases/json/json-data-sql-server#sql-server-2025-changes. Worth checking that against your production requirements before you commit the 445k-row table to it.

Thanks

Hi,

The Suite naming change was not documented in the 10.2 migration guide. That was our oversight.

Studio switches Suite to the ABP version used by the solution; that is the downgrade prompt you encountered. Suite 10.7 therefore cannot be used to regenerate a solution that remains on 10.4. The compatibility fix has been merged into 10.7 and will ship in a 10.7 package.

For your current 10.4 solution, the safest temporary path is to keep the legacy relationship names and database tables. This is a simpler alternative to the rename migration I sent earlier. If you have already replaced the drop/create operations with a safe rename and applied it successfully, you can keep that result. Otherwise:

  1. Remove the migration or migrations created by these regenerations, newest first, using EF Core migrations remove. If one was applied only to a development database, roll that database back to the preceding migration first, then remove it. Do not roll back a production database containing data this way.
  2. Keep the code generated for the new properties, but restore the relationship-related changes from source control: WorkerCompanies back to WorkerCompany, AddToCompanies / RemoveFromCompanies back to AddCompany / RemoveCompany, and the previous DbContext mappings. Do the same for CompanyRepresentativeCompany.
  3. Delete the new plural join entity files generated by Suite.
  4. Restore the previous GUID values in every regenerated test seed contributor and test file.
  5. Build the solution, then create the migration again. It must contain only the AddColumn operations for the new properties and no operations for AppWorkerCompany or AppCompanyRepresentativeCompany. Do not apply it if either join table appears in the migration.

Until then, with Suite 10.4, avoid regenerating any entity that was created before this naming change and has a many-to-many relation. Once a 10.7 package containing the compatibility fix is available, upgrade the solution and Suite together.

Thanks

Hi,

The layout components now unsubscribe from PageLayout when they are disposed, so a notification raised while the page is being torn down can no longer reach a discarded component. This is in for LeptonX 5.7.0.

Your ticket has been refunded.

Thanks

Hi,

The Type dropdown lists the claim types defined in your application, and it's empty because no claim type has been created yet. You can create them on Administration > Identity management > Claim types. If that menu item isn't there, check the AbpIdentity.ClaimTypes permission of your role - it's a host side permission, so tenant users don't get it.

Nothing is actually saved when you leave both fields blank. No empty claim is created for the user, the toast only means the request went through.

We'll change the modal to show a message instead of an empty dropdown when there is no claim type defined.

Thanks

Hi,

ContentToolbar and Breadcrumbs subscribe to the scoped PageLayout with anonymous async handlers and never remove them, so a layout notification can still reach a component the renderer has already discarded. This will be fixed in LeptonX 5.7.0.

Until then, replace both components with subclasses that keep the handlers in fields and unsubscribe on dispose:

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components.ApplicationLayout.Common;

namespace MyProject.Blazor.Client.Theming;

public class SafeContentToolbar : ContentToolbar, IDisposable
{
    private bool _disposed;

    protected override Task OnInitializedAsync()
    {
        // Not calling base, it attaches the anonymous handlers.
        PageLayout.ToolbarItems.CollectionChanged += OnToolbarItemsCollectionChanged;
        PageLayout.PropertyChanged += OnPageLayoutPropertyChanged;
        return Task.CompletedTask;
    }

    private async void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (_disposed)
        {
            return;
        }

        try
        {
            await RenderAsync();
        }
        catch (ObjectDisposedException)
        {
        }
    }

    private async void OnPageLayoutPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (_disposed)
        {
            return;
        }

        try
        {
            await InvokeAsync(StateHasChanged);
        }
        catch (ObjectDisposedException)
        {
        }
    }

    public void Dispose()
    {
        _disposed = true;
        PageLayout.ToolbarItems.CollectionChanged -= OnToolbarItemsCollectionChanged;
        PageLayout.PropertyChanged -= OnPageLayoutPropertyChanged;
    }
}

SafeBreadcrumbs : Breadcrumbs is the same shape, subscribing to PageLayout.BreadcrumbItems.CollectionChanged instead, with await InvokeAsync(StateHasChanged) in both handlers.

Register them in the ConfigureServices of both your .Blazor and .Blazor.Client modules:

using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components.ApplicationLayout.Common;

context.Services.Replace(ServiceDescriptor.Transient<ContentToolbar, SafeContentToolbar>());
context.Services.Replace(ServiceDescriptor.Transient<Breadcrumbs, SafeBreadcrumbs>());

You can drop both classes and the registrations once you upgrade to 5.7.0.

The support ticket is the right place for LeptonX, the theme packages are not in the abpframework/abp repository. The framework side you opened at https://github.com/abpframework/abp/issues/26075 is tracked there.

Thanks

hi

I will check this case.

Thanks.

Hi,

The naming change was introduced in Suite 10.2 to support multiple many-to-many relations to the same entity. Existing entities generated before 10.2 are not handled safely during regeneration.

For now, do not apply the generated migration with DropTable("AppWorkerCompany") and CreateTable("AppWorkerCompanies"). Keep the generated AddColumn operation for your new property, but replace the join-table drop/create operations with a safe rename:

migrationBuilder.DropForeignKey(
    name: "FK_AppWorkerCompany_AppCompanies_CompanyId",
    table: "AppWorkerCompany");

migrationBuilder.DropForeignKey(
    name: "FK_AppWorkerCompany_AppWorkers_WorkerId",
    table: "AppWorkerCompany");

migrationBuilder.DropPrimaryKey(
    name: "PK_AppWorkerCompany",
    table: "AppWorkerCompany");

migrationBuilder.RenameTable(
    name: "AppWorkerCompany",
    newName: "AppWorkerCompanies");

migrationBuilder.RenameIndex(
    name: "IX_AppWorkerCompany_CompanyId",
    table: "AppWorkerCompanies",
    newName: "IX_AppWorkerCompanies_CompanyId");

migrationBuilder.RenameIndex(
    name: "IX_AppWorkerCompany_WorkerId_CompanyId",
    table: "AppWorkerCompanies",
    newName: "IX_AppWorkerCompanies_WorkerId_CompanyId");

migrationBuilder.AddPrimaryKey(
    name: "PK_AppWorkerCompanies",
    table: "AppWorkerCompanies",
    columns: new[] { "WorkerId", "CompanyId" });

migrationBuilder.AddForeignKey(
    name: "FK_AppWorkerCompanies_AppCompanies_CompanyId",
    table: "AppWorkerCompanies",
    column: "CompanyId",
    principalTable: "AppCompanies",
    principalColumn: "Id",
    onDelete: ReferentialAction.Cascade);

migrationBuilder.AddForeignKey(
    name: "FK_AppWorkerCompanies_AppWorkers_WorkerId",
    table: "AppWorkerCompanies",
    column: "WorkerId",
    principalTable: "AppWorkers",
    principalColumn: "Id",
    onDelete: ReferentialAction.Cascade);

Use the same pattern for AppCompanyRepresentativeCompany → AppCompanyRepresentativeCompanies, and reverse these operations in Down.

After regeneration, update your hand-written calls to the new method names and remove the old join entity files after checking that they contain no custom code. For the generated test data, restore the previous Guid.Parse(...) values in the regenerated seed contributor and its regenerated tests. Suite 10.5 and later generate stable test GUIDs.

Suite 10.4 has no option to keep the old naming convention. We will add compatibility handling for entities generated with the legacy naming convention.

Thanks

Showing 151 to 160 of 12921 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.8.0-preview. Updated on November 02, 2026, 06:56
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.