Root cause
What to verify in your app
var book = await _bookRepository.GetAsync(id);
     book.AuthorId = input.AuthorId; // set the FK scalar
     // or set book.Author = await _authorRepository.GetAsync(input.AuthorId);
     await _bookRepository.UpdateAsync(book, autoSave: true);
var claims = new List<Claim> { new Claim(AbpClaimTypes.UserId, userId.ToString()) };
     using (_currentPrincipalAccessor.Change(claims))
     {
         await _bookRepository.UpdateAsync(book, autoSave: true);
     }
ABP 8.3+ behavior (applies to 9.2.3)
Minimal working example
public class BookAppService : ApplicationService
  {
      private readonly IRepository<Book, long> _bookRepository;
      public BookAppService(IRepository<Book, long> bookRepository)
      {
          _bookRepository = bookRepository;
      }
      public async Task UpdateAuthorAsync(long id, long? newAuthorId)
      {
          var book = await _bookRepository.GetAsync(id); // tracked
          book.AuthorId = newAuthorId;
          await _bookRepository.UpdateAsync(book, autoSave: true); // triggers ApplyAbpConcepts
          // After save, LastModificationTime and LastModifierId should be updated (if CurrentUser.Id exists)
      }
  }
var book = await _bookRepository.GetAsync(id);
  _ = ObjectMapper.Map(input, book); // ensure AuthorId ends up different
  await _bookRepository.UpdateAsync(book, autoSave: true);
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.
Root cause
Fix (recommended)
Reduce auth cookie size
Use tokens that don’t bloat headers
IIS-specific mitigations (if you still need more room)
Verify no unnecessary cookies are sent
Minimal ABP-side checklist
public class MyClaimsContributor : IAbpClaimsPrincipalContributor
    {
        public Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
        {
            var identity = context.ClaimsPrincipal.Identities.First();
            // Remove or avoid adding large/duplicate claims here
            return Task.CompletedTask;
        }
    }
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.
Why this happens
Fixes (pick one or combine)
Reduce the amount of data stored in the cookie
Switch to reference tokens (prevent large cookies to the frontend)
Increase header limits on your front-end/reverse proxy if absolutely necessary
Ensure antiforgery/cookie settings don’t add extra cookies unnecessarily
Practical steps to reduce cookie size in ABP
IIS-specific mitigation (optional)
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.
<div id="lpx-wrapper" class="lpx-layout lpx-layout--side">
      <MainHeader />
      <div class="lpx-container">
        <SideMenu />
        <div class="lpx-content-container">
          <CustomSubmenu />
          <div class="lpx-topbar-container">
            <div class="lpx-topbar"><Breadcrumbs /></div>
          </div>
          <div class="lpx-content-wrapper">
            <div class="lpx-content">
              <CustomPageActions />
              @Body
            </div>
          </div>
          <footer><Footer /></footer>
        </div>
      </div>
      <MobileNavbar />
    </div>
No estás usando los componentes de layout del tema
El layout registrado no es el de LeptonX o se reemplazó completamente
Configure<LeptonXThemeBlazorOptions>(options =>
    {
        options.Layout = typeof(Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components
            .ApplicationLayout.SideMenu.SideMenuLayout);
        // o tu CustomApplicationLayout, pero conservando estructura + clases LeptonX
    });
Falta del bundle de estilos del tema (Blazor WASM/WebApp con Global Assets)
CSS aislado que sobreescribe variables/clases del tema
Mezcla de namespaces de TopMenu y SideMenu
¿Debo agregar un CSS al componente?
Checklist rápido:
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.
What to request
How to submit the request
Interim workaround (minimal replacement)
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.
A) Use the theme’s replaceable component hook to customize the layout header/toolbar area where the collapse icon lives
Example registration (in your ThemeModule or a shared module initialized at app bootstrap):
import { NgModule } from '@angular/core';
import { ReplaceableComponentsService } from '@abp/ng.core';
import { eThemeLeptonXComponents } from '@abp/ng.theme.lepton-x'; // adjust import to your version
import { AccessibleSidebarToggleComponent } from './accessible-sidebar-toggle.component';
@NgModule({
  declarations: [AccessibleSidebarToggleComponent],
  exports: [AccessibleSidebarToggleComponent]
})
export class ThemeCustomizationModule {
  constructor(rc: ReplaceableComponentsService) {
    rc.add({
      key: eThemeLeptonXComponents.Navbar, // or the exact header/toolbar key used by your layout
      component: AccessibleSidebarToggleComponent,
    });
  }
}
B) Implement the toggle component by binding to LeptonX/Theme Shared layout state (do not re-implement state)
Example component:
import { Component, HostListener, ChangeDetectionStrategy } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
// Layout service location may differ by version; it’s typically in @abp/ng.theme.shared or @abp/ng.theme.lepton-x
import { LayoutService } from '@abp/ng.theme.shared'; // adjust import path to your version
@Component({
  selector: 'app-accessible-sidebar-toggle',
  template: `
    <button
      type="button"
      class="menu-collapse-icon"
      [attr.aria-label]="(isCollapsed$ | async) ? 'Expand navigation' : 'Collapse navigation'"
      [attr.aria-expanded]="!(isCollapsed$ | async)"
      (click)="toggleSidebar()"
      (keydown)="onKeydown($event)"
    >
      <i class="bi" [ngClass]="(isCollapsed$ | async) ? 'bi-filter-right' : 'bi-filter-left'"></i>
    </button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AccessibleSidebarToggleComponent {
  // Expose collapsed state from the theme’s layout service
  isCollapsed$: Observable<boolean> = this.layout.state$.pipe(map(s => !!s?.sidebarCollapsed));
  constructor(private layout: LayoutService) {}
  toggleSidebar(): void {
    const cur = this.layout.getState()?.sidebarCollapsed ?? false;
    this.layout.setState({ sidebarCollapsed: !cur });
  }
  onKeydown(e: KeyboardEvent): void {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      this.toggleSidebar();
    }
  }
  // Optional: expand on focus to mirror hover
  @HostListener('focusin')
  onFocusIn(): void {
    const cur = this.layout.getState()?.sidebarCollapsed ?? false;
    if (cur) {
      this.layout.setState({ sidebarCollapsed: false });
    }
  }
}
Notes:
C) Keep hover-trigger behavior
D) Where to place the toggle
E) Persisting user choice (optional)
// On app init
const saved = localStorage.getItem('sidebarCollapsed') === 'true';
layout.setState({ sidebarCollapsed: saved });
// When state changes
layout.state$.subscribe(s => localStorage.setItem('sidebarCollapsed', String(!!s?.sidebarCollapsed)));
F) Minimal template-only alternative
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.
A) Build and place Angular into Host/wwwroot
B) Ensure Host serves static files and SPA fallback In YourProjectHttpApiHostModule.cs (or Program.cs if using minimal hosting), inside OnApplicationInitialization (order matters):
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
    var app = context.GetApplicationBuilder();
    var env = context.GetEnvironment();
    app.UseAbpRequestLocalization();
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseAbpSecurityHeaders();
    app.UseHttpsRedirection();
    app.UseCorrelationId();
    // Serve SPA static files (Angular build in wwwroot)
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAbpOpenIddictValidation();
    app.UseAuthorization();
    app.UseSwagger();
    app.UseAbpSwaggerUI(options =>
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
    });
    app.UseAuditing();
    app.UseAbpSerilogEnrichers();
    app.UseConfiguredEndpoints();
    // SPA fallback: return index.html for non-file, non-API requests
    app.Use(async (ctx, next) =>
    {
        await next();
        if (ctx.Response.StatusCode == 404 &&
            !System.IO.Path.HasExtension(ctx.Request.Path.Value) &&
            !ctx.Request.Path.Value.StartsWith("/api", StringComparison.OrdinalIgnoreCase))
        {
            ctx.Request.Path = "/index.html";
            ctx.Response.StatusCode = 200;
            await next();
        }
    });
}
Alternative controller-based redirect (older practice that also works on Azure App Service):
public class HomeController : AbpController
{
    public ActionResult Index()
    {
        return Redirect("~/index.html" + HttpContext.Request.QueryString);
    }
}
C) Azure App Service specifics
app.Use(async (ctx, next) =>
{
    ctx.Request.Scheme = "https";
    await next();
});
D) Unified domain configuration Set host appsettings.json consistently for single-domain SPA+API:
E) Angular environment configuration environment.prod.ts:
F) IdentityServer client records In DbMigrator appsettings (or wherever you seed IdentityServer clients), ensure the SPA client:
G) Why you were seeing the API login page If index.html isn’t found or served, requests fall through to API endpoints (e.g., /account/login via MVC/Identity) and you see the API login instead of the Angular SPA. The SPA fallback middleware and correct placement of index.html fix this.
H) Multitenancy with subdomains (optional) If you run tenants on subdomains on the same app service and still serve SPA from the host:
Configure<AbpTenantResolveOptions>(options =>
{
    options.AddDomainTenantResolver("{0}.your-app.azurewebsites.net");
});
Configure<AbpAccountOptions>(options =>
{
    options.IsTenantMultiDomain = true;
    options.GetTenantDomain = (httpContext, info) =>
        Task.FromResult(string.IsNullOrWhiteSpace(info.Name)
            ? "https://your-app.azurewebsites.net"
            : $"https://{info.Name}.your-app.azurewebsites.net");
});
Configure<AbpAccountIdentityServerOptions>(options =>
{
    options.IsTenantMultiDomain = true;
    options.GetTenantDomain = (httpContext, ctx, info) =>
        Task.FromResult(string.IsNullOrWhiteSpace(info.Name)
            ? "https://your-app.azurewebsites.net"
            : $"https://{info.Name}.your-app.azurewebsites.net");
});
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.
A. Where to add Output Caching
B. Service registration (HttpApi.Host) In Program.cs (or Startup), register OutputCache policies alongside ABP’s standard pipeline:
// Program.cs (HttpApi.Host) builder.Services.AddOutputCache(options => { options.DefaultExpirationTimeSpan = TimeSpan.FromSeconds(30); options.AddPolicy("Default", policy => policy .Expire(TimeSpan.FromSeconds(120)) .SetVaryByHeader("Authorization")); });
// keep your existing ABP, authentication and CORS configurations here
C. Middleware order (HttpApi.Host) Add UseOutputCache in the correct order. For .NET 8, the typical order is:
var app = builder.Build();
// ... existing ABP middlewares app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseAbpRequestLocalization();
// IMPORTANT: enable output caching here app.UseOutputCache();
app.UseUnitOfWork(); app.UseAuditing();
// ABP maps endpoints here app.UseConfiguredEndpoints();
app.Run();
D. Use OutputCache attributes on controllers (in .HttpApi) Continue using attributes on your controllers (in the .HttpApi project). Example:
[OutputCache( PolicyName = "Default", VaryByRouteValueNames = new[] { nameof(id) })] [Authorize] // if required [ApiController] [Route("api/my-endpoint")] public class MyController : ControllerBase { [HttpGet("{id}")] public async Task<MyDto> GetAsync(Guid id) { ... } }
For query variants:
[OutputCache( PolicyName = "Default", VaryByQueryKeys = new[] { nameof(FilterInputDto.Id), nameof(FilterInputDto.SearchText), nameof(FilterInputDto.IsActive), nameof(FilterInputDto.Sorting) })]
E. Verifying headers and behavior
F. Why it didn’t work when controllers were in .HttpApi
G. Why you got 401 when moving controllers to .Web
H. Common pitfalls to double-check
I. Is Output Caching officially supported under .HttpApi?
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.
public class MyDataSeedContributor : IDataSeedContributor, ITransientDependency
  {
      private readonly ILocalizationTextManager _textManager;
      private readonly ICurrentTenant _currentTenant;
      public MyDataSeedContributor(ILocalizationTextManager textManager, ICurrentTenant currentTenant)
      {
          _textManager = textManager;
          _currentTenant = currentTenant;
      }
      public async Task SeedAsync(DataSeedContext context)
      {
          using (_currentTenant.Change(context?.TenantId))
          {
              // Portuguese example
              await _textManager.SetAsync("LeptonX", "FilterMenu", "pt-BR", "Filtrar menu");
              // Add other languages as needed
              await _textManager.SetAsync("LeptonX", "FilterMenu", "en", "Filter menu");
          }
      }
  }
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.
Cause
Fix
public override void OnApplicationInitialization(ApplicationInitializationContext context)
  {
      var app = context.GetApplicationBuilder();
      var env = context.GetEnvironment();
      if (env.IsDevelopment())
      {
          app.UseDeveloperExceptionPage();
      }
      app.UseAbpRequestLocalization();
      app.UseStaticFiles();          // 1: physical wwwroot
      app.UseAbpStaticFiles();       // 2: embedded static files from ABP modules
      app.UseRouting();
      app.UseAuthentication();
      app.UseJwtTokenMiddleware();
      app.UseAbpClaimsMap();
      app.UseAuthorization();
      app.UseAuditing();
      app.UseConfiguredEndpoints();
  }
public class DocsThemeGlobalContributor : BundleContributor
  {
      public override void ConfigureBundle(BundleConfigurationContext context)
      {
          var style = context.Files;
          // styles
          style.AddIfNotContains("/libs/@fortawesome/fontawesome-free/css/all.min.css");
          var script = context.Files;
          // scripts
          script.AddIfNotContains("/libs/jquery/jquery.js");
          script.AddIfNotContains("/libs/select2/js/select2.full.min.js");
          script.AddIfNotContains("/libs/moment/moment.js");
          // add any i18n files you actually use:
          // script.AddIfNotContains("/libs/select2/js/i18n/en.js");
      }
  }
That’s Font Awesome not loading. Once /libs/@fortawesome/fontawesome-free/webfonts/... are served correctly (steps 1–3), the icons will render.
Quick checklist for your screenshots
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.
 
                                