Sorting field sent in the GetListAsync request (a PagedAndSortedResultRequestDto / GetIdentityUsersInput-like DTO).GetListInput.Sorting.@* YourProject.Blazor/Pages/Identity/UserManagement.razor *@
@using Volo.Abp.Identity.Blazor.Pages.Identity
@using Volo.Abp.DependencyInjection
@attribute [ExposeServices(typeof(UserManagement))]
@attribute [Dependency(ReplaceServices = true)]
@inherits UserManagement
Sorting before loading:// YourProject.Blazor/Pages/Identity/UserManagement.razor.cs
using System.Threading.Tasks;
namespace YourProject.Blazor.Pages.Identity;
public partial class UserManagement
{
protected override async Task UpdateGetListInputAsync()
{
await base.UpdateGetListInputAsync();
if (string.IsNullOrWhiteSpace(GetListInput.Sorting))
{
// Pick any valid field exposed by the backend DTO:
// e.g. "UserName", "Name", "Email", etc.
GetListInput.Sorting = "UserName asc";
}
}
}
Now the page will always request users sorted by UserName asc unless the UI sets another sorting.
If you want clicking column headers to sort, ensure the page sets:
GetListInput.Sorting = CurrentSorting;
(where CurrentSorting is the value produced by the ABP CRUD/grid base page logic). This is the same pattern used in ABP Blazor CRUD pages to pass sorting to the backend.
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.
"/Account/Login" with missing ".AspNetCore.Antiforgery.*" cookie is almost always a cookie not being stored/sent back during the login POST inside that browser session./Account/Login fails exactly like your log.AuthServer:Authority you use in the mobile OIDC config is https://... (not http://...) and the browser is actually hitting HTTPS.Secure and then dropped/not returned by modern browsers.UseCookiePolicy() early.In your *.Web (or the host project that serves the /Account/* pages), add:
ConfigureServices
context.Services.AddSameSiteCookiePolicy();
OnApplicationInitialization (before auth middleware that writes cookies)
app.UseCookiePolicy();
This is the approach used to fix browser-specific login cookie issues.
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.
Your setting Configure<AbpAntiForgeryOptions>(o => o.AutoValidate = false) disables ABP’s global [AbpAutoValidateAntiforgeryToken] behavior for MVC/API endpoints, but your error is coming from Microsoft’s built-in Razor Pages antiforgery filter:
Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter
and the failing endpoint is the Razor Page /Account/Login.
In ABP (with the Account module), /Account/Login is a Razor Page and it’s expected to be protected by antiforgery because it is a cookie-based, browser login page. For mobile OIDC (Authorization Code + PKCE), you typically should not POST to /Account/Login from the mobile app at all. The mobile app should start the OIDC authorize flow in a system browser/custom tab, and the browser will handle cookies + antiforgery correctly.
If you still want to allow posting to /Account/Login without antiforgery (not recommended), do it specifically for that Razor Page by overriding the login page model and suppressing antiforgery validation.
/Account/Login from the mobile app/connect/authorize (system browser)/connect/token (back-channel)/Account/Login from the app. That endpoint is designed for interactive browser login./Account/Login, override the Razor Page and ignore antiforgery*.HttpApi.Host (or *.Web) project, create:Pages/Account/Login.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Account.Web.Pages.Account;
namespace MyCompany.MyApp.HttpApi.Host.Pages.Account;
[IgnoreAntiforgeryToken] // disables Razor Pages antiforgery validation for this page
public class LoginModel : Volo.Abp.Account.Web.Pages.Account.LoginModel
{
public LoginModel(
Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemeProvider,
Microsoft.Extensions.Options.IOptions<Volo.Abp.Account.Web.AbpAccountOptions> accountOptions,
Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Identity.IdentityOptions> identityOptions,
Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributorCache contributorCache)
: base(schemeProvider, accountOptions, identityOptions, contributorCache)
{
}
}
Pages/Account/Login.cshtml
Pages/Account/Login.cshtml to override the UI (you can copy the original ABP login page markup from the Account module as described in ABP’s “customize login page” approach). The key part for antiforgery is the Login.cshtml.cs with [IgnoreAntiforgeryToken].AutoValidateAntiforgeryTokenAttribute from MvcOptions/Account/Login./Account/Login in the first place for OIDC.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.
ICurrentUser.FindImpersonatorUserId() != null). So the fastest way to debug is to verify whether impersonation is still active (claims/cookies) and whether the toolbar item is still being contributed.CurrentUser.FindImpersonatorUserId() is NOT null.null, the “back” button will not render. In that case, impersonation may still “look like it worked” (you’re logged in as the user) but the impersonator info wasn’t persisted (usually due to cookies/auth pipeline changes, custom account controller, reverse proxy cookie issues, etc.).For MVC, the button is not “magic”; it comes from the impersonation UI integration. If you customized your toolbar/layout/theme, you may have removed the contributor/view component that renders it.
Make sure you followed the MVC impersonation UI setup:
FindImpersonatorUserId() != null.POST ~/Account/BackToImpersonator exists (it’s the action the button posts to).If you’ve overridden AccountController, confirm it still inherits from the impersonation-enabled base controller as required by the docs.
To prove it’s only a UI/toolbar problem (not claims), temporarily add this to your main layout (or a toolbar area) and test while impersonating:
@using Volo.Abp.Account.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@inject IHtmlLocalizer<AccountResource> L
<form method="post" data-ajaxForm="false" action="~/Account/BackToImpersonator">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-link text-danger">
@L["BackToImpersonator"]
</button>
</form>
There is a known case where the button is not visible depending on responsive/mobile toolbar placement (especially with LeptonX). In older versions it was fixed by upgrading (example reported/fixed in later versions for mobile view). Even on desktop, if your theme moved the user menu into a different place, the button may now be under the username menu instead of the top bar.
If you have custom IToolbarContributor code, ensure it’s contributing to the toolbar your layout uses (e.g., StandardToolbars.Main). A wrong toolbar name check can prevent the item from being added.
Links I verified:
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.
/Account/Register?isExternalLogin=True to auto-create/link the user.The provided antiforgery token was meant for a different claims-based user than the current user.System.Collections.Generic.KeyNotFoundException: The given key 'IsSeeding' was not present in the dictionary.Cns.Cloud.Apps.Users.UserCreatedEventHandler.HandleEventAsync(...).So you have two issues:
UserCreatedEventHandler throws, which breaks the request (this is the primary failure)./Error?httpStatusCode=400 with a changed user context.IsSeeding exists (use TryGetValue / ContainsKey, or provide a default). Example pattern:public Task HandleEventAsync(EntityCreatedEto<IdentityUserEto> eventData)
{
// Example: if you stored extra properties somewhere, never index directly
// var isSeeding = dict["IsSeeding"]; // <- unsafe
var isSeeding = false;
if (eventData.Properties != null &&
eventData.Properties.TryGetValue("IsSeeding", out var value) &&
value is bool b)
{
isSeeding = b;
}
if (isSeeding)
{
return Task.CompletedTask;
}
// normal logic...
return Task.CompletedTask;
}
(Adapt to your actual dictionary/object; the key point is don’t index with [...] unless you’re 100% sure it’s there.)
/Account/Register?isExternalLogin=True appears).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.
IEmailSender with your own implementation that reads the current tenant’s configuration and sends using OAuth (e.g., Microsoft Graph, Gmail API, or SMTP with OAuth2 via MailKit if that’s your provider).Define your own setting names and register them with a SettingDefinitionProvider. ABP settings are automatically resolved per-tenant.
public static class TenantEmailOAuthSettings
{
private const string Prefix = "MyApp.Email.OAuth";
public const string Provider = Prefix + ".Provider"; // e.g. "MicrosoftGraph", "Gmail"
public const string TenantId = Prefix + ".TenantId";
public const string ClientId = Prefix + ".ClientId";
public const string ClientSecret = Prefix + ".ClientSecret";
public const string FromAddress = Prefix + ".FromAddress";
public const string FromDisplayName = Prefix + ".FromDisplayName";
}
Then, create a custom settings UI page (Blazor Server) similar to how custom setting pages are added (same technique as “white labeling” examples: define settings + implement an app service using ISettingManager + add a UI page/group).
IEmailSender with a tenant-aware OAuth senderImplement IEmailSender and read settings using ISettingProvider (which resolves values in the context of the current tenant).
using System.Net.Mail;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Emailing;
using Volo.Abp.Settings;
public class TenantOAuthEmailSender : IEmailSender, ITransientDependency
{
private readonly ISettingProvider _settingProvider;
public TenantOAuthEmailSender(ISettingProvider settingProvider)
{
_settingProvider = settingProvider;
}
public async Task SendAsync(MailMessage mail, bool normalize = true)
{
// Read per-tenant OAuth configuration
var provider = await _settingProvider.GetOrNullAsync(TenantEmailOAuthSettings.Provider);
var clientId = await _settingProvider.GetOrNullAsync(TenantEmailOAuthSettings.ClientId);
var clientSecret = await _settingProvider.GetOrNullAsync(TenantEmailOAuthSettings.ClientSecret);
// Use these to send via your chosen OAuth provider (Graph/Gmail/etc.)
// (Implementation depends on provider; this is where you call Graph API, etc.)
throw new NotImplementedException();
}
public Task SendAsync(string to, string subject, string body, bool isBodyHtml = true)
=> SendAsync(new MailMessage { Subject = subject, Body = body, IsBodyHtml = isBodyHtml, To = { to } });
public Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true)
=> SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml });
public Task QueueAsync(string to, string subject, string body, bool isBodyHtml = true)
=> SendAsync(to, subject, body, isBodyHtml); // or integrate with background jobs
}
Register it by replacing ABP’s default email sender:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Modularity;
public class MyAppEmailModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(ServiceDescriptor.Transient<IEmailSender, TenantOAuthEmailSender>());
}
}
If you want tenants to edit email-related settings themselves, ABP can gate this via tenant features (SaaS). In practice, you enable the relevant tenant feature in the SaaS tenant management screen (this is how built-in “Emailing” settings visibility is controlled).
ABP’s default UI won’t cover OAuth flows. You typically:
IEmailSender implementation.Sources (verified)
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.
changePasswordToken is not an OpenIddict/OpenID Connect token type and there is no built-in OAuth/OIDC endpoint (like /connect/token) that “uses” it in ABP.
In ABP, a “change password / reset password token” is an ASP.NET Core Identity user token (generated by UserManager.GeneratePasswordResetTokenAsync(...) / related APIs) and it must be consumed by an ABP Account endpoint (HTTP API) that performs the password change/reset (not the OpenIddict token endpoint).
So the correct flow is typically:
/connect/token with password / authorization_code / etc.).If your goal is: “I want to exchange changePasswordToken for an access token at /connect/token”, that’s not supported by default. You would need to implement a custom OpenIddict extension grant (ITokenExtensionGrant) and validate your token yourself, then issue an access token.
Minimal outline (ABP’s OpenIddict extension grant mechanism):
OpenIddictServerOptions.GrantTypesITokenExtensionGrant implementation in AbpOpenIddictExtensionGrantsOptionsHandleAsync(...), validate the incoming token and return SignInResult to generate a token response.Sources (validated):
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.
Yes, AutoMapper and Mapperly can coexist in the same ABP 10+ solution. ABP 10 switched ABP modules/templates to use Mapperly by default, but ABP still provides both AutoMapper and Mapperly integration packages, so you can keep existing AutoMapper profiles while using Mapperly elsewhere (or for ABP-provided modules).
What “coexistence” practically means in ABP
IObjectMapper / ObjectMapper.Map(...).Recommended best practices / common pitfalls when using both
context.Services.AddAutoMapperObjectMapper<MyBlazorModule>();
// or
context.Services.AddMapperlyObjectMapper<MyBlazorModule>();
- Then set the context where you map (e.g., in an `ApplicationService` / Blazor page base):
ObjectMapperContext = typeof(MyBlazorModule);
- Otherwise, ABP may fall back to the *default* provider and you can get “no mapping found” errors (especially visible in UI layers like Blazor).
Avoid ambiguous/duplicate mappings for the same source/destination pair
Decide which one is the default provider for ObjectMapper.Map
ObjectMapper.Map<TSource, TDestination> to use Mapperly, ensure your startup/host module registers Mapperly as the default object mapper:context.Services.AddMapperlyObjectMapper();
- If you keep AutoMapper as default, you’ll do the analogous AutoMapper default registration instead.
Framework design intent in ABP 10
Is coexistence “officially supported long-term” or only transitional?
Migration guidance / strategy for large AutoMapper profile bases (phased approach)
MapperBase<>, TwoWayMapperBase<>), then remove the corresponding AutoMapper maps.ObjectMapper (ABP abstraction) where possible, and only inject concrete Mapperly mappers when you need very specific behavior.Sources (validated)
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.
DbContext/transactions alive; the Unit Of Work (UOW) is. ABP’s UOW defines the database connection/transaction boundary and disposes it when the UOW ends.IQueryable/DbContext-backed object and use it later).What to do (recommended ABP approach)
Do not inject repositories/DbContext and run EF code directly inside Blazor components.
Keep components “UI only” and call Application Services (or domain services) instead.
Ensure each operation is wrapped in its own UOW (short-lived).
[UnitOfWork] or IUnitOfWorkManager.Begin(...) to scope it to that single method call.Example (explicit UOW):
public class MyBlazorActionService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IMyEntityRepository _repo;
public MyBlazorActionService(IUnitOfWorkManager unitOfWorkManager, IMyEntityRepository repo)
{
_unitOfWorkManager = unitOfWorkManager;
_repo = repo;
}
public async Task DoSomethingAsync()
{
await using var uow = _unitOfWorkManager.Begin(isTransactional: true);
// db work here
await uow.CompleteAsync();
}
}
Never keep a transaction open waiting for user interaction.
In Blazor it’s tempting to “start transaction on button A, commit on button B”. Don’t do that. Between those clicks you may block rows/tables (especially in PostgreSQL depending on what you touched). Instead:
Avoid holding EF Core queryables across events.
Don’t cache IQueryable, repositories, or anything that implicitly depends on an ambient UOW and then enumerate it later. Materialize results inside the same method/UOW (e.g., ToListAsync) and return DTOs to the component.
About your workaround
Creating a new scope per handler can work, but it’s not the intended pattern in ABP. The intended pattern is: Blazor component → call app service → app service method runs in its own UOW → done. That gives you the “per action” scope you want without manual service resolution.
https://abp.io/docs/latest/framework/architecture/domain-driven-design/unit-of-work
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.