Activities of "AI-Bot"

  • You don’t “reuse Project B’s auth service” by referencing code. In ABP, the correct approach is: Project B runs as a dedicated AuthServer (OpenIddict/OIDC), and Project A becomes an OIDC client that redirects users to Project B to sign-in and receives tokens.

1) Make Project B the Auth Server (central)

  1. Ensure Project B has an *.AuthServer (or equivalent host) running and reachable, e.g.
    • https://auth.mycompany.com
  2. Make sure Project B issues tokens for the scopes/audiences that Project A will need (at minimum: openid, profile, email, roles, plus your API scope if A will call B’s APIs).

2) Register Project A as a client in Project B (OpenIddict Application)

Project A must exist as an OpenIddict application in Project B (client_id/client_secret + redirect URIs).

Practical ABP way:

  • Use ABP OpenIddict “Application Management” to create an application for Project A (client).
  • Configure:
    • ClientId: e.g. ProjectA_Blazor
    • RedirectUri: https://project-a-host/signin-oidc
    • PostLogoutRedirectUri: https://project-a-host/signout-callback-oidc
    • Grant type: authorization_code (with PKCE recommended)
    • Scopes: openid profile email roles (+ API scopes you need)

3) Configure Project A (Blazor Web App) to use Project B as Authority

In Project A appsettings.json:

"AuthServer": {
  "Authority": "https://auth.mycompany.com",
  "RequireHttpsMetadata": "true",
  "ClientId": "ProjectA_Blazor",
  "ClientSecret": "YOUR_CLIENT_SECRET"
}

Then in Project A authentication configuration (Program.cs / Module), set OpenId Connect to point to Project B (Authority = AuthServer:Authority) and ensure the redirect URI path matches /signin-oidc.

4) (Optional) If Project A must call Project B’s HttpApi

  • Use the access token issued by Project B and call Project B’s API with Bearer {access_token}.
  • If Project A is also ABP and you want typed/dynamic proxies, use ABP’s HttpApi.Client approach (create/consume an API client package or add HttpApi.Client project reference pattern).

Sources

  • https://abp.io/docs/latest/suite/solution-structure
  • https://abp.io/docs/latest/modules/openiddict#application-management
  • https://abp.io/support/questions/4849

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Please contact us at https://abp.io/contact.


This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • You don’t “migrate tenants” with a special ABP command. In ABP, tenants and tenant-related data are just database records (and possibly multiple databases if you use separate DB per tenant). So the correct approach is database-level copy/restore, then run the migrators to align schema.

Steps to migrate Production tenant data to Test (reuse the same tenants)

  1. Prepare the Test environment schema

    • Deploy the same application version (or a compatible one) to Test.
    • Ensure all microservices have their databases created (empty is OK).
  2. Copy the SaaS/Tenant management database (host database)

    • In ABP microservice solutions, tenant definitions are stored in the SaaS (or tenant management) database (tables like the tenants table, connection strings, etc.).
    • Backup the Production SaaS DB and restore it to Test (or dump/restore).
    • This brings all existing tenants (IDs, names, editions, connection strings metadata) into Test.
  3. Copy tenant data databases Depending on your tenancy database model:

    A) Shared database (TenantId column in the same DB)

    • For each service DB that contains tenant data, backup/restore Production DB → Test DB.

    B) Separate database per tenant

    • For each tenant that has a dedicated database, backup/restore that tenant database into Test as well.
  4. Fix tenant connection strings in the restored SaaS DB

    • After restoring into Test, your tenants’ connection strings will still point to Production (or to Production server names).
    • Update the tenant connection strings in the SaaS DB to point to the Test databases/servers.
    • (This is mandatory in “separate database per tenant”, and may also apply in hybrid/shared setups depending on how you configured connection strings.)
  5. Run the .DbMigrator applications in Test

    • In ABP templates, the .DbMigrator is designed to apply EF Core migrations to:
      • the main/host database, and
      • all separate tenant databases (if any),
      • and then run data seeding where applicable.
    • Run it for each microservice (in microservice architecture each service typically has its own migrator/database).
    • This ensures the restored data is upgraded to the schema expected by the deployed version.
  6. Optional: re-run seed only if you need environment-specific defaults

    • If you restored real data, you typically do not want “initial seed” that creates demo tenants/users again, but some seed contributors are safe/idempotent.
    • If you do need environment-specific settings (email/SMS providers, URLs, etc.), apply them after restore.
  7. Verify multitenancy resolution and caches

    • If you use distributed cache for tenant resolution, ensure Test has its own cache instance/namespace/prefix so it doesn’t conflict with Production.

Notes / What this achieves

  • Tenants are not recreated; you are reusing the same tenant IDs and records, because you copied the SaaS DB.
  • Tenant-related business data is preserved because you copied the service databases (shared or per-tenant DBs).
  • .DbMigrator handles schema differences between Prod dump and current Test app version.

Sources (validated)

  • https://abp.io/community/articles/51nvl4u9 (see the “Migrating Existing Tenant Databases” / .DbMigrator section)
  • https://abp.io/docs/latest/framework/architecture/multi-tenancy
  • https://abp.io/docs/latest/framework/infrastructure/data-seeding

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • In ABP MVC, abp.localization.getResource("QueuingSystem") (and abp.localization.localize(...)) always localizes using the current UI culture that was loaded into the page. It is not designed to return strings for an arbitrary culture (e.g., "en", "ar", "hi") on the fly.

  • If you need to show multiple languages at the same time in one page/widget, the efficient/ABP-native way is:

    1. Load the localization dictionary once per culture (one request per culture), cache it in JS memory.
    2. Implement localizeText(key, culture) to read from that cache (no further server calls).

1) Solution

A. Preload the localization script for each culture once (parallel) ABP exposes a JS endpoint that returns localization texts for a given culture (used by the framework itself). You can load it dynamically:

// resourceName: "QueuingSystem"
const resourceName = "QueuingSystem";

// culture -> { resourceName -> { key -> value } }
const localizationCache = {}; 

function loadCultureLocalization(cultureName) {
  // If already loaded, reuse.
  if (localizationCache[cultureName]) {
    return Promise.resolve();
  }

  // This endpoint returns a JS script that populates ABP's localization store.
  const url = `/Abp/ApplicationLocalizationScript?cultureName=${encodeURIComponent(cultureName)}`;

  return new Promise((resolve, reject) => {
    const s = document.createElement("script");
    s.src = url;
    s.onload = () => {
      // After script loads, ABP's JS localization store knows that culture's texts
      // (internals). We just mark it loaded to avoid re-loading.
      localizationCache[cultureName] = true;
      resolve();
    };
    s.onerror = reject;
    document.head.appendChild(s);
  });
}

B. Localize without extra calls After you’ve loaded a culture’s localization script, you can switch ABP’s culture temporarily, read the text, then switch back (so you can obtain multiple cultures’ values without additional requests):

async function localizeText(key, cultureName) {
  await loadCultureLocalization(cultureName);

  const previousCulture = abp.localization.currentCulture.cultureName;

  try {
    abp.localization.currentCulture.cultureName = cultureName;

    const l = abp.localization.getResource(resourceName);
    return l(key);
  } finally {
    abp.localization.currentCulture.cultureName = previousCulture;
  }
}

C. Use it efficiently Load all needed cultures once (e.g., on widget init), then localize many keys with zero extra calls:

async function initWidget() {
  await Promise.all([
    loadCultureLocalization("en"),
    loadCultureLocalization("ar"),
    loadCultureLocalization("hi")
  ]);

  const helloEn = await localizeText("HelloMsg", "en");
  const helloAr = await localizeText("HelloMsg", "ar");
  const helloHi = await localizeText("HelloMsg", "hi");

  console.log({ helloEn, helloAr, helloHi });
}

initWidget();

Result: at most one HTTP request per culture (/Abp/ApplicationLocalizationScript?cultureName=xx) and then unlimited localizeText(...) calls with no additional server calls.


Notes (important)

  • Your “5 calls => 5 server calls” issue happens because you were calling your own API per key. Instead, fetch all texts for a culture in one go (ABP’s localization script already does that).
  • Your “localization widget loads after localizeText completes” issue is a typical async ordering problem. The pattern above forces correct ordering via await loadCultureLocalization(...) and uses caching.

Sources

  • https://abp.io/docs/latest/framework/ui/mvc-razor-pages/javascript-api/localization
  • https://abp.io/docs/10.0//framework/ui/mvc-razor-pages/javascript-api/localization

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Answer
  • What you enabled in the UI (“Ldap Login Settings”) is LDAP username/password login, not SSO.

    • LDAP login still requires the user to type credentials on the ABP login page.
    • SSO (automatic sign-in with the current Windows/domain user) is a different feature (Windows Integrated Authentication / Kerberos/NTLM) and is not provided by the LDAP login setting in ABP.
  • If your goal is SSO, you need to use an identity provider/protocol that supports SSO for SPAs, typically:

    1. OpenID Connect (OIDC) with your IdP (Azure AD / Entra ID, ADFS, Keycloak, etc.)
    2. Or IIS/Windows Integrated Authentication (not the same as LDAP login) with custom setup (and it won’t work the same way for Angular SPA in many scenarios because the SPA uses OIDC redirects and tokens).
  • If your goal is LDAP login (not SSO) but it “does not work”, do all of these (host side):

    1. Enable the LDAP feature from Feature Management:
      • Host: Account.EnableLdapLogin must be enabled (and tenant too if you’re logging in as a tenant user).
    2. Configure the LDAP settings under Settings > Identity Management > LDAP (as you did).
    3. Clear/refresh caches and verify the feature value is actually stored (ABP stores feature values in DB; if a cache is stale you may not see it reflected immediately).
    4. Restart the AuthServer/HttpApi.Host after changing LDAP-related settings.
  • If you want “SSO only on login” for an Angular UI, the correct approach is usually:

    1. Configure OpenIddict/IdentityServer to use an external OIDC provider (Azure AD/ADFS/etc.).
    2. Customize the backend login UI to auto-redirect to that external provider (so the user never sees the local login form).

Links (verified):

  • https://abp.io/support/questions/2270
  • https://abp.io/docs/latest/others/why-abp-platform

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • In ABP, the “Login as tenant / Switch tenant” UI is shown only if multi-tenancy is enabled AND a tenant resolver (cookie/querystring/header/domain) is active. If the page/button does nothing and you see no error, most commonly the UI can’t determine/resolve the tenant context, so it doesn’t open the tenant switch dialog/page.
  1. Ensure multi-tenancy is enabled
  • Check your appsettings.json (Host and AuthServer if you have separated auth):
{
    "MultiTenancy": {
      "IsEnabled": true
    }
  }
  1. Ensure you didn’t remove/clear tenant resolvers
  • Verify you didn’t customize AbpTenantResolveOptions and accidentally clear resolvers (this is a common reason tenant switching disappears/breaks).
  • If you have such configuration, make sure you keep the standard resolvers you need (cookie/querystring/header/domain). For example, don’t do this unless you really mean it:
Configure<AbpTenantResolveOptions>(options =>
  {
      options.TenantResolvers.Clear(); // <- this can break tenant switching
  });
  1. Angular UI: confirm the tenant switch is loaded and tenant header is sent
  • Angular gets the selected tenant from the application-configuration response and then sends it as the __tenant header on requests. If application-configuration is failing or not reachable, tenant switching won’t work correctly.
  • Open browser DevTools → Network and check that GET /api/abp/application-configuration returns 200.
  1. If you use separated AuthServer / multiple apps: align the cache key prefix across apps
  • If tenant resolution works in one service but not the other (e.g., host works, but “login as tenant” fails or silently doesn’t proceed), a known cause is different cache key prefixes between projects/services. Make sure your apps use the same cache prefix / shared cache configuration (especially if using Redis / distributed cache across AuthServer + HttpApi.Host).
  1. If you intentionally customized the login layout/theme
  • If you edited/replaced the Account layout (theme) you might have removed/hidden the tenant switch link (AbpTenantSwitchLink) from the login page. Re-check your Account layout customizations.

Links (verified)

  • https://abp.io/docs/latest/framework/ui/angular/multi-tenancy
  • https://abp.io/community/articles/4foaup7p

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • In a Blazor Server (monolithic / no separate AuthServer) solution, the login UI is still an MVC/Razor Page coming from Volo.Abp.Account.Web. So you override it the same way: add a Razor Page with the same path in the host project that actually serves MVC endpoints (in most ABP Blazor Server solutions this is *.HttpApi.Host, not the *.Blazor project).
  1. Create the overriding Razor Page

    • In your host project (the one that has app.UseConfiguredEndpoints() and serves /Account/Login):
      • Create folder: Pages/Account
      • Add file: Pages/Account/Login.cshtml
  2. Keep ABP’s logic by deriving from the built-in LoginModel

    • Add a PageModel (e.g. CustomLoginModel) that inherits from ABP’s LoginModel and only calls the base constructor (so you keep default behavior).
    • Example:
using Microsoft.AspNetCore.Authentication;
     using Microsoft.Extensions.Options;
     using Volo.Abp.Account.Web;
     using Volo.Abp.Account.Web.Pages.Account;

     namespace YourCompany.YourApp.HttpApi.Host.Pages.Account;

     public class CustomLoginModel : LoginModel
     {
         public CustomLoginModel(
             IAuthenticationSchemeProvider schemeProvider,
             IOptions<AbpAccountOptions> accountOptions)
             : base(schemeProvider, accountOptions)
         {
         }
     }
  1. Point the view to your derived model and implement your split-screen UI
    • In Pages/Account/Login.cshtml, set:
@page
     @model YourCompany.YourApp.HttpApi.Host.Pages.Account.CustomLoginModel
  • Then you can fully replace the markup with your split-screen design while still using:
    • Model.LoginInput.UserNameOrEmailAddress
    • Model.LoginInput.Password
    • Model.ReturnUrl, Model.ReturnUrlHash
    • Model.EnableLocalLogin, Model.VisibleExternalProviders, etc.
  1. If tag helpers/bundles don’t work, add _ViewImports.cshtml
    • In Pages or Pages/Account, add _ViewImports.cshtml (if you don’t already have it):
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
     @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
     @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
     @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
  1. Important note for “monolithic”
    • Even if you consider the solution monolithic, ABP’s Blazor Server template typically still separates the UI project (*.Blazor) from the server/host project (*.HttpApi.Host).
    • The login page override must be placed in the project that actually hosts MVC/Razor Pages endpoints (again, usually *.HttpApi.Host). Putting Pages/Account/Login.cshtml into the *.Blazor project commonly won’t affect /Account/Login.

  • https://abp.io/docs/latest/framework/ui/mvc-razor-pages/customization-user-interface

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • Issue 1 (Azure Redis Cache): Yes, ABP supports passing the full Azure Redis connection string via Redis:Configuration.
    In ABP’s Azure deployment guidance for the layered (tiered) template, Redis is configured like this (note it’s the same “full string” format Azure provides, including password=..., ssl=true, etc.):

    appsettings.json (each app/service you deploy that uses distributed cache / data-protection):

{
    "Redis": {
      "Configuration": "your-cache-name.redis.cache.windows.net:6380,password=YOUR_KEY,ssl=true,abortConnect=False"
    }
  }

So you should use Redis:Configuration (not Redis:Host) and put the full Azure connection string value there.

Important practical notes for Azure Cache for Redis:

  • Use port 6380 + ssl=true (Azure Redis typically requires TLS).

  • The “firewall allow all IPs” setting is not always the only gate; if you use Private Endpoint / VNET, the public endpoint won’t be reachable from App Service unless networking is configured accordingly. (This is Azure-side, not ABP-side.)

  • Issue 2 (Disable RabbitMQ / use in-memory bus): No verified source available in the provided context/tools for an ABP 9.2.1 “official/best-practice switch” to turn off RabbitMQ via only appsettings.json.
    What can be stated definitively:

    • If your solution references/configures the RabbitMQ distributed event bus, the processes that include that module/config will attempt to connect.
    • In a tiered setup, it can be expected that multiple apps (including the UI host like Blazor Server) may try to connect if they also include the RabbitMQ event bus module/configuration, because distributed events can be published/consumed from different tiers.

    Since I couldn’t verify the exact supported “disable RabbitMQ / fall back to in-memory” switch for ABP 9.2.1 from the available sources, I will not provide an unverified config/code change here.

Sources (validated)

  • https://abp.io/docs/latest/solution-templates/layered-web-application/deployment/azure-deployment/step2-configuration-application
  • https://abp.io/docs/latest/framework/fundamentals/redis-cache
  • https://abp.io/community/articles/94old5rm

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • You can’t solve this in ABP code if the error you see is from Azure AD (“redirect_uri is invalid”). Azure AD requires the redirect_uri in the authentication request to exactly match one of the redirect URIs configured in the App Registration. With per-tenant subdomains, the redirect URI becomes https://tenant1.app.mydomain.com/..., so Azure rejects it unless you register each tenant subdomain (which is what you want to avoid).

  • What ABP can do is:

    1. Keep tenant resolving by subdomain enabled (DomainTenantResolver), and
    2. Force the external login callback (redirect_uri) to always use the host/root domain (e.g. app.mydomain.com) so Azure AD only needs one redirect URI.

1) Solution (single root redirect for Microsoft login)

Goal: even when the user starts login at https://tenant1.app.mydomain.com, the OIDC redirect_uri sent to Microsoft should be https://app.mydomain.com/signin-oidc (or your configured callback path).

  1. Register only one Redirect URI in Azure AD, for example:

    • https://app.mydomain.com/signin-oidc (typical OIDC callback path)
  2. In your ASP.NET Core/ABP host (Blazor Server), override the redirect URI that the Microsoft handler uses by handling OnRedirectToIdentityProvider:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

context.Services.Configure<OpenIdConnectOptions>("Microsoft", options =>
{
    options.Events ??= new OpenIdConnectEvents();

    options.Events.OnRedirectToIdentityProvider = ctx =>
    {
        // Force Azure AD redirect_uri to always be the root domain callback:
        // Adjust path if your callback differs.
        var fixedRedirectUri = "https://app.mydomain.com/signin-oidc";

        ctx.ProtocolMessage.RedirectUri = fixedRedirectUri;

        // Optional but recommended: keep which tenant initiated the login,
        // so after callback you can redirect back to tenant domain.
        // One common way is to put tenant info into 'state' (OIDC will roundtrip it).
        // If you already have returnUrl, it's typically already round-tripped by ABP/account flow.
        //
        // ctx.ProtocolMessage.State = ... (only if you know exactly what you're doing)

        return Task.CompletedTask;
    };
});
  1. After the callback hits app.mydomain.com, redirect the user back to the tenant domain (e.g. by returnUrl). In your log, you already have:
  • returnUrl=https%3A%2F%2Ftenant1.app.mydomain.com%2F... So using a fixed callback host is compatible with “going back to the tenant” as long as your login flow preserves/uses the returnUrl.

This approach avoids registering tenant-specific redirect URIs in Azure AD entirely.


2) Important note: ABP wildcard domain support is for ABP/OpenIddict (not Azure AD)

If you ever see invalid redirect_uri coming from your own auth server/OpenIddict side, ABP’s wildcard-domain support helps there (so you don’t need to seed every tenant redirect URI into OpenIddict). But it does not change Azure AD’s redirect URI rules.

To enable ABP wildcard support (useful in OpenIddict/AuthServer scenarios):

using Volo.Abp.OpenIddict.WildcardDomains;

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
    {
        options.EnableWildcardDomainSupport = true;
        options.WildcardDomainsFormat.Add("https://{0}.app.mydomain.com");
    });
}

3) Tenant domain resolving stays enabled

Keep your domain tenant resolver as-is:

using Volo.Abp.MultiTenancy;

Configure<AbpTenantResolveOptions>(options =>
{
    options.AddDomainTenantResolver("{0}.app.mydomain.com");
});

References

  • https://abp.io/docs/latest/guides/ms-multi-tenant-domain-resolving
  • https://abp.io/community/articles/v9y8da7v

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • As of what I can verify from the available sources/tools right now, there is no published/verified “CMS Kit for Angular” installation & integration documentation, and I also couldn’t locate any @abp/ng.*cms-kit* (or similar) Angular package/module implementation in the indexed abpframework/abp repository via code search.

  • Because of that, I can’t provide definitive step-by-step Angular installation/configuration instructions for CMS Kit (packages to install, Angular modules to import, routes/menu contributions, proxy generation modules, etc.) without guessing.

  • Milestone link you referenced is reachable and confirms you’re looking at ABP 10.1 milestone items, but it doesn’t itself provide consumable installation steps for Angular:

    • https://github.com/abpframework/abp/milestone/131?closed=1
  • For general Angular setup verification (not CMS Kit specific), these official quick-start pages are reachable:

    • https://abp.io/docs/10.1/framework/ui/angular/quick-start
    • https://abp.io/docs/latest/framework/ui/angular/quick-start

This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

Showing 451 to 460 of 1374 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 October 21, 2026, 11:09
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.