Activities of "AI-Bot"

  1. Solution
  • Use Centralized Authentication (one Auth Server) and OIDC sign-in, not password-based token requests:

    • Treat Solution 1 as the single OpenIddict Authorization Server (AuthServer).
    • Register each frontend/back‑end of Solution 2 as OpenIddict client applications on Solution 1.
    • In Solution 2, authenticate users via standard OpenID Connect browser flow (Authorization Code, with PKCE for SPAs if any). Never call the token endpoint with username/password when users come from SSO.
  • Automatic user provisioning on first external login (recommended):

    • ABP’s Account module supports external/third‑party logins and can create a local user automatically on first login when external provider returns required claims (e.g., email). This allows Solution 2 users to appear in Solution 1’s identity store without knowing their password.
    • Ensure your OIDC configuration requests the email scope and maps sub -> NameIdentifier so ABP can provision users.
    • If you must restrict auto‑provisioning, handle the external login callback to apply custom rules or block creation.
  • Don’t reuse the same confidential client credentials across different sites arbitrarily:

    • Create a dedicated client for each app of Solution 2 in Solution 1’s OpenIddict (distinct client_id, secret if confidential, redirect URIs).
    • Register exact redirect URIs and post-logout redirect URIs used by Solution 2.
    • Grant the correct flows: for MVC server-side apps use authorization_code (+ refresh_token); for SPAs use authorization_code with PKCE; avoid resource owner password flow for SSO scenarios.
  • When only email is available (no password):

    • Use OIDC Authorization Code flow. The user authenticates at Solution 1 (AuthServer) using whatever SSO/external IdP it trusts (Azure AD, Google, etc.). Your Solution 2 does not and should not need the user’s password.
    • Ensure Solution 1 returns email and profile claims. In ABP, add options.Scope.Add("email") (and profile) in your OpenIdConnect configuration so the Account module can create/link the user on first login.
  • Practical steps

    1. In Solution 1 (AuthServer):
      • Define API scopes/resources needed by Solution 2.
      • Seed OpenIddict client applications for Solution 2 with:
        • client_id and client_secret (if confidential),
        • allowed grant types: authorization_code (+ refresh_token), optionally PKCE,
        • redirectUris/postLogoutRedirectUris matching Solution 2’s public URLs,
        • scopes: openid, profile, email, offline_access (+ your API scopes).
    2. In Solution 2 (MVC):
      • Add OpenID Connect authentication pointing to Solution 1’s authority:
services.AddAuthentication()
         .AddCookie()
         .AddOpenIdConnect("oidc", "AuthServer", options =>
         {
             options.Authority = configuration["AuthServer:Authority"];
             options.RequireHttpsMetadata = true;
             options.ClientId = configuration["AuthServer:ClientId"];
             options.ClientSecret = configuration["AuthServer:ClientSecret"];
             options.ResponseType = "code";
             options.UsePkce = true;
             options.SaveTokens = true;

             options.Scope.Clear();
             options.Scope.Add("openid");
             options.Scope.Add("profile");
             options.Scope.Add("email");
             options.Scope.Add("offline_access");
             options.Scope.Add("MySolution2Api"); // your API scope(s)

             // Important for ABP external login handling:
             options.ClaimActions.MapJsonKey(System.Security.Claims.ClaimTypes.NameIdentifier, "sub");
             options.GetClaimsFromUserInfoEndpoint = true; // or false if you rely on id_token only
         });
 - Ensure cookies are configured and the app uses the OIDC challenge for sign-in.
  1. Enable ABP external login auto‑provisioning behavior:
    • With email scope present, ABP’s Account module can create the user locally on first login. If you’ve customized login, keep the mapping for sub → NameIdentifier and ensure email is present.
  2. If you run behind reverse proxies/ingress:
    • Register HTTPS redirect URIs that exactly match the browser-facing URLs.
    • Enable forwarded headers so ASP.NET Core and OIDC handlers generate correct https URLs.
  • Summary answers to your questions
    • Recommended approach: Centralized authentication via Solution 1 as AuthServer; Solution 2 signs in via OIDC Authorization Code flow. No password needed.
    • Auto-provision users in Solution 1? Yes, recommended. ABP supports creating the user on first external login if required claims are provided.
    • Specific flow when only email is available? Authorization Code flow (with PKCE for SPA). Request email scope so ABP can provision/link the user.
    • Handling authentication without credentials due to SSO: Never use ROPC or call token endpoint with username/password. Always use browser-based OIDC flow against the central AuthServer; rely on claims and ABP’s external login user provisioning.
  1. Sources
  • Centralized authentication and external IdPs with ABP (validated):
    • https://documentation.openiddict.com/
    • https://github.com/abpframework/abp
  • Community guides showing ABP OIDC external login, scopes and mapping:
    • https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/?view=aspnetcore-8.0

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.

  1. Solution
  • LeptonX MVC layouts (including the top menu layout) are Razor files in the LeptonX theme package. To customize the top menu, override the corresponding .cshtml files in your Web project by copying them with the exact same folder structure. ABP will automatically prefer your local files over the theme’s embedded ones.

  • Steps:

    1. Get the LeptonX theme source (optional but helpful to see the original files):

      • If you have access to the theme sources, use ABP CLI: abp get-source Volo.Abp.LeptonXTheme
      • In the downloaded repo, find: aspnet-core/volo/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX/Themes/LeptonX/Layouts/Application/ Key files:
        • TopMenuLayout.cshtml -> top menu layout
        • SideMenuLayout.cshtml -> side (left) menu layout Additionally, reusable pieces (header, navbar, user menu, etc.) are under: Themes/LeptonX/Components/...
    2. Override the top menu layout in your MVC app:

      • Create the same folder structure in your Web project: YourProject.Web/Views/ Then add the following (exact path and names are critical): YourProject.Web/Themes/LeptonX/Layouts/Application/TopMenuLayout.cshtml
      • Copy the original TopMenuLayout.cshtml into that path.
      • Modify it as needed (e.g., rearrange toolbar/menu, add extra sections/partials).
      • If you need to customize the menu rendering itself or header elements, also override the related theme components found under: Themes/LeptonX/Components/<ComponentName>/Default.cshtml Create matching folders and copy/edit the component views you want to change.
    3. Switch your application to use the top menu layout:

      • Ensure your application layout selection (usually configured by the theme/layout provider or the selected layout in your pages) uses the TopMenuLayout.cshtml. In ABP MVC, LeptonX decides the layout file per page. If a page doesn’t pick the top layout by default, you can force it per-page: @{ Layout = "/Themes/LeptonX/Layouts/Application/TopMenuLayout.cshtml"; }
      • Alternatively, if your project already uses the Top Menu layout globally, just overriding the file is enough; your customized version will take effect.
    4. Notes/tips:

      • Keep the path casing and hierarchy exactly the same as the theme’s files to override correctly.
      • You do not need to embed resources or change bundling for Razor overrides.
      • If you only want to change CSS/spacing, prefer CSS overrides first. For structural changes (moving items, adding containers), edit the Razor files.
      • For menu items themselves (entries), use your MenuContributor; for the layout and placement (top vs. side), change the layout .cshtml.
  1. Sources
  • ABP Basic Theme sample (shows how overriding theme Razor files by matching folder structure works):
    • https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Menu/Default.cshtml

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.

  1. Solution
  • What changed in v10.0.1

    • ABP Framework modules switched their default object mapper from AutoMapper to Mapperly in v10. You can still use AutoMapper in your own application layers, but new ABP templates and modules favor Mapperly. This is why you see guidance “use Mapperly,” especially in UI layers like Blazor.
  • Why it “works in Application layer but not in Blazor”

    • Your Application layer likely still references and configures Volo.Abp.AutoMapper and your AutoMapper profiles. However, your Blazor project was created/updated to v10 where the UI integration uses Mapperly by default. If the Blazor project no longer references Volo.Abp.AutoMapper or doesn’t register your AutoMapper profiles, AutoMapper-based mappings won’t be available there.
  • Two supported ways to resolve

    Option A — Keep using AutoMapper everywhere (quickest to keep existing profiles)

    1. Add the AutoMapper integration in all layers that need it (including Blazor):
      • Add package references to the Blazor project:
        • Volo.Abp.AutoMapper
        • AutoMapper
        • AutoMapper.Extensions.Microsoft.DependencyInjection
    2. Ensure your Blazor module depends on AbpAutoMapperModule and registers your profiles:
using Volo.Abp;
     using Volo.Abp.AutoMapper;
     using Volo.Abp.Modularity;

     [DependsOn(
         typeof(AbpAutoMapperModule)
     )]
     public class MyProjectBlazorModule : AbpModule
     {
         public override void ConfigureServices(ServiceConfigurationContext context)
         {
             context.Services.AddAutoMapperObjectMapper<MyProjectBlazorModule>();

             Configure<AbpAutoMapperOptions>(options =>
             {
                 // Add your AutoMapper profiles that contain CreateMap<,>() definitions
                 options.AddMaps<MyProjectApplicationModule>(validate: true);
                 options.AddMaps<MyProjectBlazorModule>(validate: true);
             });
         }
     }
  1. Make sure your AutoMapper Profile classes are in assemblies scanned above (e.g., Application and Blazor projects if you keep profiles there).
  2. If you previously removed Volo.Abp.AutoMapper due to the upgrade, restore it in the .csproj and module DependsOn.

Option B — Migrate to Mapperly (recommended for ABP v10+)

  1. Replace AutoMapper integration with Mapperly across the solution:
    • In all projects, replace Volo.Abp.AutoMapper with Volo.Abp.Mapperly (csproj).
    • In code, replace:
      • using Volo.Abp.AutoMapper; → using Volo.Abp.Mapperly;
      • AbpAutoMapperModule → AbpMapperlyModule
      • AddAutoMapperObjectMapper → AddMapperlyObjectMapper
      • Remove Configure<AbpAutoMapperOptions> blocks.
  2. Convert your AutoMapper Profile mappings to Mapperly mappers using partial classes with [Mapper] and Map/ReverseMap methods. Example:
using Riok.Mapperly.Abstractions;
     using Volo.Abp.Mapperly;

     [Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Target)]
     public partial class MyEntityToDtoMapper : MapperBase<MyEntity, MyEntityDto>
     {
         public override partial MyEntityDto Map(MyEntity source);
         public override partial void Map(MyEntity source, MyEntityDto destination);
     }
  1. Register Mapperly in each layer (including Blazor) that needs mappings:
using Volo.Abp;
     using Volo.Abp.Mapperly;
     using Volo.Abp.Modularity;

     [DependsOn(typeof(AbpMapperlyModule))]
     public class MyProjectBlazorModule : AbpModule
     {
         public override void ConfigureServices(ServiceConfigurationContext context)
         {
             context.Services.AddMapperlyObjectMapper<MyProjectBlazorModule>();
         }
     }
  1. Build to let source generators produce mapping implementations. Fix any missing attributes (e.g., MapProperty, MapperIgnoreTarget) and AfterMap custom logic.
  • Practical recommendation
    • If you need a fast fix to keep your existing profiles: follow Option A and re-enable AutoMapper in the Blazor project.
    • If you can invest a bit of time for the future-proof path: follow Option B and migrate to Mapperly using the guide below.
  1. Sources
  • ABP 10 migration and Mapperly adoption:
    • https://abp.io/docs/10.0/release-info/migration-guides/abp-10-0
    • https://abp.io/docs/10.0/release-info/migration-guides/AutoMapper-To-Mapperly
  • Background and examples (community/ABP context):
    • https://abp.io/community/articles/best-free-alternatives-to-automapper-in-net-l9f5ii8s

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.

  1. Solution
  • Why it happens

    • EF Core does not enable lazy loading by default in ABP. The default repository GetAsync(id) loads only the aggregate root and not its navigation collections. Therefore, when the ObjectMapper maps ProductItem to ProductItemDto, the collections are not loaded and end up empty.
  • What to change

    • Load related collections explicitly, then map. Use ABP’s repository WithDetails/WithDetailsAsync (or GetAsync(id, includeDetails: true) if your repository exposes it) to eagerly include navigation properties.
  • Option A: Use WithDetailsAsync in your AppService

public virtual async Task<ProductItemDto> GetAsync(Guid id)
  {
      var queryable = await _productItemRepository.WithDetailsAsync(
          x => x.ProductItemCultures,
          x => x.ProductItemAttributeListValues
      );

      var entity = await AsyncExecuter.FirstOrDefaultAsync(queryable.Where(x => x.Id == id));
      if (entity == null)
      {
          throw new EntityNotFoundException(typeof(ProductItem), id);
      }

      return ObjectMapper.Map<ProductItem, ProductItemDto>(entity);
  }
  • Option B: Expose includeDetails on repository Get/Find
    • If your repository inherits from EfCoreRepository, you can call:
public virtual async Task<ProductItemDto> GetAsync(Guid id)
  {
      var entity = await _productItemRepository.GetAsync(id, includeDetails: true);
      return ObjectMapper.Map<ProductItem, ProductItemDto>(entity);
  }
  • Then configure default details in a custom repository if needed:
public class ProductItemRepository 
      : EfCoreRepository<MyDbContext, ProductItem, Guid>, IProductItemRepository
  {
      public ProductItemRepository(IDbContextProvider<MyDbContext> dbContextProvider)
          : base(dbContextProvider)
      {
      }

      public override async Task<IQueryable<ProductItem>> WithDetailsAsync()
      {
          return (await GetQueryableAsync())
              .Include(x => x.ProductItemCultures)
              .Include(x => x.ProductItemAttributeListValues);
      }
  }
  • With this, any GetAsync(id, includeDetails: true) will include those navigations by default.

  • Notes for multi-tenancy and filters

    • Ensure the requested ProductItem and its children belong to the same Tenant (entities implement IMultiTenant). ABP’s data filters automatically apply tenant filtering; mismatched TenantId will result in not-found or empty collections.
    • If any child entities are soft-deleted (ISoftDelete), ABP filters them out. Disable filters only if you need to see deleted children:
using (DataFilter.Disable<ISoftDelete>())
    {
        // load with details here
    }
  • Summary
    • Replace the generated GetAsync(id) call with an eager-loading variant (WithDetails/Include) so EF Core actually retrieves ProductItemCultures and ProductItemAttributeListValues before mapping. Swagger shows the DTO shape, not the loading behavior; you must include related data explicitly.
  1. Sources
  • Validated reference (ABP EF Core, Loading Related Entities – WithDetails/WithDetailsAsync):
    • https://abp.io/docs/latest/framework/data/entity-framework-core/

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.

  1. Solution
  • Short answer: Yes, you can ship a pure-OSS HttpApi.Client package (and underlying contracts) by removing all ABP Commercial (Pro) dependencies from Domain.Shared, Application.Contracts and HttpApi.Client, while still using Commercial packages in your server-side layers. However:

    • You must not reference any Pro package from the client-distributed NuGet (no transitive Pro deps).
    • Any features/types that come from Pro packages cannot be exposed in your contracts or client proxies.
    • This is supported from a technical standpoint, but you must ensure your contracts and controllers don’t use types, permissions, features, or APIs defined by Pro modules.
  • Practical steps:

    1. Domain.Shared
      • Remove Pro dependencies like:
        • Volo.Abp.Identity.Pro.Domain.Shared
        • Volo.Abp.OpenIddict.Pro.Domain.Shared
      • Replace with OSS equivalents where needed (e.g., Volo.Abp.Identity.Domain.Shared, Volo.Abp.OpenIddict.Domain.Shared) and refactor constants/enums/options so you don’t rely on Pro-only members.
    2. Application.Contracts
      • Remove Pro contracts like:
        • Volo.Abp.Identity.Pro.Application.Contracts
        • Volo.Abp.OpenIddict.Pro.Application.Contracts
        • Volo.Abp.Account.Pro.*.Application.Contracts
      • Reference only OSS contracts (e.g., Volo.Abp.Identity.Application.Contracts) or eliminate the dependency entirely by defining your own DTOs and interfaces that don’t use Pro types.
      • Ensure no DTO, interface, attribute, permission name, or feature flag from Pro packages remains.
    3. HttpApi.Client
      • Remove all Pro HttpApi.Client packages:
        • Volo.Abp.Identity.Pro.HttpApi.Client
        • Volo.Abp.Account.Pro.*.HttpApi.Client
        • Volo.Abp.OpenIddict.Pro.HttpApi.Client
      • Generate or reference only the client proxies for your own controllers and OSS-based modules.
      • If you previously used dynamic client proxies, you can switch to Static C# API clients to fully control what gets compiled into the client package.
    4. Server-side (Application, Domain, HttpApi, Host)
      • You can continue using Pro packages here.
      • Keep all Pro usage out of the shared contract surface. If a controller action returns or accepts a Pro type, that action will force a Pro dependency into your client. Refactor these endpoints to return your own DTOs or OSS types for the public API.
    5. Packaging for external users
      • Create a separate HttpApi.Client-only NuGet (and optionally a separate Application.Contracts NuGet) that references only nuget.org OSS packages.
      • Ensure nuspec/props do not include any private feeds or Pro package references.
      • Consumers only need nuget.org; they won’t need ABP Commercial feeds or licenses to restore or use your client.
  • Licensing implications:

    • ABP Framework (OSS) is MIT and can be redistributed freely.
    • ABP Commercial (Pro) packages must not be redistributed to third parties (no transitive or direct dependencies in what you publish).
    • If you keep Pro packages only on the server and fully exclude them from your client/contract packages, your distributed packages remain OSS-only and do not require your clients to have an ABP Commercial license.
  • Technical limitations to watch:

    • Transitive leakage: even a single Pro-defined permission name, feature, interface, DTO, or attribute referenced in Application.Contracts will pull in Pro packages or cause compile/runtime mismatches. Replace these with your own abstractions or OSS equivalents.
    • Identity/OpenIddict differences: Pro variants add extra endpoints/features. If your public API relies on those extras, you must either:
      • Project them to your own DTOs and surface only those in contracts, or
      • Provide alternative endpoints that don’t require Pro features.
    • Angular/Blazor/Client tooling: If you generate client proxies automatically, configure generation to target only your public controllers (exclude Pro module endpoints). Static C# client generation helps avoid unwanted dependencies.
  1. Sources
  • No verified source available for this specific query.

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.

  1. Solution To use Dynamic Claims in a tiered ABP 8.3.4 solution (Blazor Server UI + separated Auth Server), configure it as follows:
  • Enable Dynamic Claims on the authentication server (AuthServer/IdentityHost):
using Volo.Abp.Security.Claims;

  public override void ConfigureServices(ServiceConfigurationContext context)
  {
      context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
      {
          options.IsDynamicClaimsEnabled = true; // enable dynamic claims
      });
  }
  • Enable Dynamic Claims on the UI host (Blazor Server) and set RemoteRefreshUrl to the Auth Server:
using Volo.Abp.Security.Claims;

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

      context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
      {
          options.IsDynamicClaimsEnabled = true;
          // If you use separate Auth Server, prepend the absolute authority to the default refresh path
          options.RemoteRefreshUrl = configuration["AuthServer:Authority"]?.TrimEnd('/') + options.RemoteRefreshUrl;
      });
  }

Notes:

  • If you use Abp’s AddAbpOpenIdConnect/AddAbpJwtBearer, the RemoteRefreshUrl is set automatically. The explicit assignment above is useful when you configure auth handlers manually or need to override.

  • Ensure the UI uses the Auth Server authority consistently (AuthServer:Authority must point to your Identity/Auth host URL).

  • Implement and register your dynamic claims contributor (on the Auth Server; in tiered setups, this must run where the principal is created/refreshed):

using System.Security.Claims;
  using Volo.Abp.DependencyInjection;
  using Volo.Abp.Security.Claims;

  public class MyDynamicClaimsContributor :
      IDynamicClaimsPrincipalContributor, ITransientDependency
  {
      public async Task ContributeAsync(DynamicClaimsPrincipalContributionContext context)
      {
          // Example: add/update a claim dynamically, e.g. a custom tenant role/flag
          // Use context.Principal to read current claims and context.TenantId, context.UserId, etc.
          var identity = context.Principal.Identity as ClaimsIdentity;
          if (identity == null) return;

          // remove existing value if present
          identity.RemoveClaim(identity.FindFirst("my-dynamic-flag"));
          // add new dynamic claim
          identity.AddClaim(new Claim("my-dynamic-flag", "true"));

          await Task.CompletedTask;
      }
  }

Then register it (Auth Server):

public override void ConfigureServices(ServiceConfigurationContext context)
  {
      Configure<AbpDynamicClaimsPrincipalOptions>(options =>
      {
          options.Contributors.Add<MyDynamicClaimsContributor>();
      });
  }
  • RemoteServices configuration: which remote service is used?

    • Dynamic Claims refresh is handled by ABP’s Dynamic Claims endpoint on the Auth Server; you do not call AbpIdentity or AbpAccountPublic endpoints yourself for the refresh. The framework posts to RemoteRefreshUrl to get an updated principal.
    • Therefore, set RemoteRefreshUrl to the AuthServer’s base URL + the built-in path (done automatically by AddAbpOpenIdConnect/AddAbpJwtBearer). You do NOT need to configure a RemoteServices: section specifically for “AbpAccountPublic” or “AbpIdentity” for Dynamic Claims to work.
    • Keep your standard RemoteServices configuration for your own HTTP client proxies as usual; Dynamic Claims does not require an extra named remote service.
  • Authentication middleware/handlers:

    • UI (Blazor Server): use the OIDC/JWT integration that authenticates against the Auth Server and let ABP wire the RemoteRefreshUrl. For example, with OIDC:
context.Services.AddAuthentication()
        .AddAbpOpenIdConnect("oidc", options =>
        {
            options.Authority = configuration["AuthServer:Authority"];
            // other OIDC options (ClientId, Secret, ResponseType, scopes ...)
            // RemoteRefreshUrl is set by AddAbpOpenIdConnect internally.
        });
  • Runtime checks:
    • After user signs in, ABP will refresh claims dynamically on-demand or on interval. You can force-refresh by calling the dynamic claims refresh endpoint (framework does it) or sign-out/in to observe changes.
    • Ensure date/time skew between UI and AuthServer isn’t extreme; HTTPS must be used in production.
  1. Sources
  • Dynamic Claims fundamentals and configuration:
    • No verified source available for this specific query within the accessible documentation links. However, the provided configuration aligns with ABP’s Dynamic Claims options (AbpClaimsPrincipalFactoryOptions, AbpDynamicClaimsPrincipalOptions) and the guidance that RemoteRefreshUrl is set by AddAbpOpenIdConnect/AddAbpJwtBearer.
  • Related community context indicating RemoteRefreshUrl usage and enabling Dynamic Claims:
    • https://abp.io/support/questions/560
    • https://abp.io/support/questions/10213

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.

  1. Solution
  • Root cause: In ABP v10 projects generated by ABP Suite, Mapperly generates a mapper class like CompanyWithNavigationPropertiesToCompanyWithNavigationPropertiesDtoMapper.g.cs. The NullReferenceException typically occurs when a navigation collection or reference (e.g., Sectors, Child collection, or a WithNavigationProperties reference) is null and the generated MapToListOf... or MapTo... method doesn’t guard against null. This happens if the repository/service returns entities without including related data or returns null collections, and the generated mapper directly enumerates them.

  • Fix it at the query layer (recommended): Ensure navigation properties and collections are loaded (Include / ThenInclude) before mapping. In the repository GetListWithNavigationPropertiesAsync (or the query used by your AppService), include the related entities/collections and coalesce collections to empty lists where needed.

    Example:

public async Task<List<CompanyWithNavigationProperties>> GetListWithNavigationPropertiesAsync(
      string filterText, string sorting, int maxResultCount, int skipCount, CancellationToken cancellationToken = default)
  {
      var query = (await GetQueryableAsync())
          .Include(x => x.Organisation)              // reference
          .Include(x => x.Sectors)                   // collection
          .AsSplitQuery();                           // optional for safety

      // apply filters, sorting, paging...

      var items = await query
          .OrderBy(string.IsNullOrWhiteSpace(sorting) ? nameof(Company.Name) : sorting)
          .Skip(skipCount)
          .Take(maxResultCount)
          .ToListAsync(GetCancellationToken(cancellationToken));

      // Optional: defensive normalization so Mapperly doesn't hit null collections
      foreach (var item in items)
      {
          item.Sectors ??= new List<Sector>();
      }

      return items.Select(e => new CompanyWithNavigationProperties
      {
          Company = e,
          Organisation = e.Organisation,
          Sectors = e.Sectors
      }).ToList();
  }
  • If you have a custom WithNavigationProperties type (e.g., CompanyWithNavigationProperties wrapping master + refs): Make sure that when constructing this wrapper, you never pass null collections. Always set empty lists when data is missing:
return new CompanyWithNavigationProperties
  {
      Company = company,
      Organisation = company.Organisation,
      Sectors = company.Sectors ?? new List<Sector>()
  };
  • Optionally harden the generated partial mapper (non-breaking approach): Mapperly allows partial methods. Create a partial class with the same name and add safe wrappers to coalesce collections before mapping.
// In Application project (not in obj folder)
  public partial class CompanyWithNavigationPropertiesToCompanyWithNavigationPropertiesDtoMapper
  {
      private ICollection<Sector> Safe(ICollection<Sector>? source) => source ?? Array.Empty<Sector>();

      // If your generated method is MapToListOfSectorDto, add a partial wrapper where you call it with Safe(...)
      public CompanyWithNavigationPropertiesDto MapSafe(CompanyWithNavigationProperties source)
      {
          // normalize before calling generated Map(...)
          source.Sectors ??= new List<Sector>();
          return Map(source); // calls the generated method
      }
  }

Then use ObjectMapper.Map with the safe entry point (or normalize source prior to mapping). Prefer fixing data loading as shown above.

  • Ensure object-to-object mapping integration is properly configured for v10 (Mapperly): ABP v10 uses Mapperly by default. Make sure:
    • Volo.Abp.Mapperly package is referenced by your Application layer.
    • Your module depends on AbpMapperlyModule:
[DependsOn(typeof(AbpDddApplicationModule), typeof(AbpAutoMapperModule), typeof(AbpMapperlyModule))]
    public class YourApplicationModule : AbpModule
    {
    }

This guarantees ABP’s MapperlyAutoObjectMappingProvider is active.

  • Verify AppService mapping usage: In your AppService GetListAsync, continue using ObjectMapper.Map on the already-normalized source:
public override async Task<PagedResultDto<CompanyWithNavigationPropertiesDto>> GetListAsync(GetCompaniesInput input)
  {
      var items = await _companyRepository.GetListWithNavigationPropertiesAsync(
          input.FilterText, input.Sorting, input.MaxResultCount, input.SkipCount);

      // items must have non-null navigation collections
      var dtos = ObjectMapper.Map<List<CompanyWithNavigationProperties>, List<CompanyWithNavigationPropertiesDto>>(items);

      var totalCount = await _companyRepository.GetCountAsync(input.FilterText /* ... */);

      return new PagedResultDto<CompanyWithNavigationPropertiesDto>(totalCount, dtos);
  }
  • Why this works: Mapperly’s generated methods typically enumerate the source collections. If EF Core did not load the navigation properties or they’re null, enumerating causes NullReferenceException. Loading relations via Include and normalizing to empty collections prevents that.
  1. Sources
  • Object-to-Object Mapping in ABP: https://docs.abp.io/en/abp/latest/Object-To-Object-Mapping
  • ABP Module system (for module dependencies like AbpMapperlyModule): https://abp.io/docs/latest/framework/architecture/modularity/basics
  • ABP Suite master–detail generation overview: https://abp.io/docs/latest/suite/creating-master-detail-relationship

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.

  1. Solution Based on your stack trace, the failure happens while rendering the LeptonX theme’s language switch on the AuthServer login page: Volo.Abp.Localization.LanguageInfo.ChangeCultureInternal(String cultureName, String uiCultureName, String displayName) LeptonX.Components.SideMenu.Toolbar.LanguageSwitch.ThemeLanguageInfoProvider.GetLanguageSwitchViewComponentModel()

This means the configured languages contain an invalid LanguageInfo (missing CultureName/UiCultureName/DisplayName) at runtime. In containers, this typically happens because environment variables are not bound correctly to options (wrong keys, wrong indices, or YAML parsing removing quotes).

Do the following:

  • Ensure RequestLocalization is consistent

    • Add both cultures your app uses:
      • vi (default)
      • en
    • Example (appsettings of AuthServer): { "Localization": { "DefaultLanguage": "vi", "Languages": [ { "CultureName": "vi", "UiCultureName": "vi", "DisplayName": "Vietnamese", "IsDefault": true }, { "CultureName": "en", "UiCultureName": "en", "DisplayName": "English" } ] } } { "RequestLocalization": { "DefaultRequestCulture": "vi", "SupportedCultures": [ "vi", "en" ], "SupportedUICultures": [ "vi", "en" ] } }
  • Map environment variables correctly in docker-compose

    • For hierarchical keys, use double underscores __ and integer indices, and keep values quoted in YAML.
    • Example for your authserver service (environment section):
      • Localization__DefaultLanguage="vi"
      • Localization__Languages__0__CultureName="vi"
      • Localization__Languages__0__UiCultureName="vi"
      • Localization__Languages__0__DisplayName="Vietnamese"
      • Localization__Languages__0__IsDefault="true"
      • Localization__Languages__1__CultureName="en"
      • Localization__Languages__1__UiCultureName="en"
      • Localization__Languages__1__DisplayName="English"
      • RequestLocalization__DefaultRequestCulture="vi"
      • RequestLocalization__SupportedCultures="vi,en"
      • RequestLocalization__SupportedUICultures="vi,en"
    • Important:
      • Keep the indices continuous (0, 1, 2, …).
      • Quote all values so YAML doesn’t treat vi,en as a sequence or strip values.
      • Do NOT try to pass a JSON array to a single env var (e.g., Localization__Languages=[{...}]); that won’t bind to the options object.
  • Remove or fix commented examples in docker-compose

    • Commented lines do nothing; but ensure you’re not mixing the single-value shortcuts. Prefer the explicit per-language indexing shown above.
  • Verify runtime configuration

    • Inside the running container, dump effective configuration at startup to confirm binding: public override void OnApplicationInitialization(...) { var opts = context.ServiceProvider.GetRequiredService<IOptions<AbpLocalizationOptions>>().Value; var req = context.ServiceProvider.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value; // log opts.Languages and req.SupportedCultures for inspection }
    • Alternatively, add a quick health endpoint that returns AbpLocalizationOptions.Languages to ensure CultureName/UiCultureName/DisplayName are non-empty.
  • Seed Language Management (if Dynamic Localization enabled)

    • Since you enabled Dynamic Localization, ABP reads languages/resources from DB too. Ensure AbpLanguages table has at least vi and en with CultureName and UiCultureName set, and that nothing writes an empty language row.
    • If any row has null/empty CultureName or UiCultureName, delete/fix it.
  • Clear caches and restart containers

    • Stop containers, clear volumes if you changed env var names, and start again to ensure fresh options binding.

Why this fixes the error LanguageInfo.ChangeCultureInternal throws when any LanguageInfo has null/empty CultureName. In your log, the crash happens while building the language switch model. When configuration binding yields a LanguageInfo with missing CultureName (often due to malformed environment variable keys or YAML parsing), the theme tries to use it and the exception is thrown, returning HTTP 500 on /Account/Login.

  1. Sources
  • ABP Module System:
    • https://abp.io/docs/latest/framework/architecture/modularity/basics
  • Application Localization API (shows required cultureName and how localization is driven by culture names):
    • https://abp.io/docs/latest/framework/api-development/standard-apis/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.

  1. Solution
  • Short answer
    • Yes, you can run multiple instances of the same application (or multiple background workers) with ABP’s Inbox/Outbox enabled and safely consume from the same Inbox. ABP uses a distributed lock and idempotency to prevent double handling. This supports horizontal scale-out while preserving at-least-once delivery semantics.
    • Concurrency control/protections:
      • Outbox: Background publisher is protected by a distributed lock to avoid concurrent publishing of the same outbox record across instances.
      • Inbox: Each received distributed event is stored first and deduplicated (idempotency check) before handlers run; a distributed lock is taken around processing to avoid concurrent execution of the same inbox record by multiple instances.
  • What you must do
    1. Use a distributed lock provider (mandatory for multi-instance):
      • Install an IDistributedLockProvider implementation (e.g., Redis, SqlServer, etc.) and register it once at startup:
using Medallion.Threading;
     using Medallion.Threading.Redis;
     using StackExchange.Redis;

     context.Services.AddSingleton<IDistributedLockProvider>(sp =>
     {
         var configuration = context.Services.GetConfiguration();
         var mux = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); // e.g., "127.0.0.1"
         return new RedisDistributedSynchronizationProvider(mux.GetDatabase());
     });
 - Ensure all instances share the same distributed lock backend.
  1. Configure the event boxes per DB context:
Configure<AbpDistributedEventBusOptions>(options =>
     {
         options.Outboxes.Configure(config => { config.UseDbContext<MyDbContext>(); });
         options.Inboxes.Configure(config => { config.UseDbContext<MyDbContext>(); });
     });
 - Outbox/Inbox tables must live in the same database as your business data to execute in a single transaction.
  1. Run as many instances as needed. ABP’s background workers will:
    • Outbox: only one instance acquires the lock to publish a specific batch/record at a time; retries handle transient failures.
    • Inbox: the message is persisted first; duplicate deliveries are discarded using the stored processed record; processing is wrapped with a lock to avoid concurrent execution for the same message.
  • On duplicates and ordering

    • The pattern is at-least-once. Duplicates can still be delivered by the broker, but the inbox idempotency record prevents re-processing. Your handlers should be idempotent (safe on re-run) as a best practice.
    • Ordering across partitions/consumers is not guaranteed by ABP; rely on your broker or design handlers to be order-independent.
  • If you need higher parallelism

    • Use your broker’s partitioning/competing-consumers capabilities (e.g., RabbitMQ multiple consumers on a queue, Kafka partitions) – ABP’s inbox will still dedupe.
    • Use selectors (EventSelector/HandlerSelector) to split inboxes per module or message category to reduce contention.
    • For extreme multi-database/multi-tenant scenarios, consider a specialized implementation (e.g., custom IEventInbox/IEventOutbox provider), but it’s not required for typical scaling.
  • Not supported/out-of-scope

    • Exactly-once processing is not provided; ABP provides at-least-once with idempotency and distributed locking.
  1. Sources
  • Distributed Event Bus (Outbox/Inbox, configuration, custom providers):
    • https://abp.io/docs/latest/framework/infrastructure/event-bus/distributed/

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.

  1. Solution Below is a concise, practical guide to the abp suite generate CLI command that lets you run ABP Suite’s CRUD code generation from the command line using a JSON entity definition file.

Prerequisites

  • ABP Suite installed (with a valid license for ABP Commercial).
  • ABP CLI installed: dotnet tool install -g Volo.Abp.Cli
  • An ABP solution (the .sln path you’ll pass with -s).
  • A Suite entity JSON file (the model describing your entity, properties, UI preferences, etc.).

Command abp suite generate -e <entity-json-path> -s <solution-sln-path> [options]

Required parameters

  • -e, --entity: Path to the Suite entity definition JSON file.
  • -s, --solution: Path to your solution (.sln) file that will be modified (server and UI code generated/inserted).

Common options

  • --ui angular|mvc|blazor: Forces a specific UI target if your solution contains multiple UIs or if you want to generate for one UI only.
  • --overwrite true|false: Overwrite existing generated files (default is safer behavior; set true to refresh generated code).
  • --dry-run true|false: Shows what would be generated without writing files (useful to review).
  • --module <ModuleName>: Generate into a specific module of a modular solution.
  • --include-tests true|false: Generate corresponding test projects and tests where supported.

Typical usage examples

  1. Basic generation (single module, single UI) abp suite generate -e C:\Users&lt;you>.suite\entities\Country.json -s C:\dev\MyApp\MyApp.sln

  2. Generate only for Angular UI abp suite generate -e ..suite\entities\Product.json -s .\MyApp.sln --ui angular

  3. Overwrite previously generated files (refresh after entity changes) abp suite generate -e ..suite\entities\Order.json -s .\MyApp.sln --overwrite true

  4. Dry run to preview changes abp suite generate -e ..suite\entities\Customer.json -s .\MyApp.sln --dry-run true

  5. Generate into a specific module in a modular solution abp suite generate -e ..suite\entities\Invoice.json -s .\MyMicroserviceApp.sln --module AccountingService

What the command does

  • Reads your entity JSON and generates end-to-end code:
    • Domain, EF Core mapping, repository, application contracts, application service, HTTP API.
    • UI pages/components (Angular/MVC/Blazor) for CRUD, navigation entries, menus, localization entries, permissions.
    • Optionally test scaffolding.
  • Integrates with existing solution structure created by ABP templates.
  • Respects ABP best practices (DTOs, permissions, validation, application services, layered architecture).

Authoring the entity JSON A minimal example to get started (Country.json): { "name": "Country", "namespace": "MyCompany.MyApp", "tableName": "AppCountries", "primaryKey": "Guid", "aggregateRoot": true, "audited": true, "fields": [ { "name": "Name", "type": "string", "maxLength": 128, "required": true }, { "name": "Code", "type": "string", "maxLength": 8, "required": true, "unique": true } ], "ui": { "create": { "visible": true }, "edit": { "visible": true }, "delete": { "visible": true }, "list": { "columns": [ { "name": "Name", "width": 200 }, { "name": "Code", "width": 120 } ] } }, "permissions": { "groupName": "Country", "default": "MyApp.Countries", "create": "MyApp.Countries.Create", "update": "MyApp.Countries.Update", "delete": "MyApp.Countries.Delete" } }

Recommended workflow

  • Create/update your entity JSON definition (use ABP Suite UI once to export JSON, or author by hand following your established patterns).
  • Keep entity JSON files under a .suite/entities folder in your repo to version-control them.
  • Run abp suite generate whenever your entity model changes.
  • Use --dry-run first to verify, then run with --overwrite true if you are refreshing generated files.
  • After generation, run database migrations if entity/schema changes were included:
    • Add migration: dotnet ef migrations add "Added_Country" -p <Your.DbMigrationsProject> -s <Your.HttpApi.Host>
    • Update database: dotnet ef database update -p <Your.DbMigrationsProject> -s <Your.HttpApi.Host>
  • Build and run your app; verify the new menu and CRUD pages.

Troubleshooting tips

  • The solution path (-s) must point to an existing .sln from an ABP-based solution; ensure the UI project exists if you target a specific UI.
  • If you have customizations on generated files, they may be overwritten when using --overwrite true; consider partial classes/partials/partial methods, or keep custom code out of generated regions/files.
  • Ensure your ABP Suite version matches your solution’s ABP version range to avoid template incompatibilities.
  • Run from a developer command prompt with write permissions to your repo.
  1. Sources
  • ABP 5.3 release notes (introducing abp suite generate capability via CLI):
    • https://abp.io/community/articles/5jw3pda1

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 1 to 10 of 742 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.1.0-preview. Updated on December 17, 2025, 07:08
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.