- Add state-aware overload to ISimpleStateCheckerSerializer/Contributor
- Features and Permissions contributors recognise their batch checker and emit a per-state record
- PermissionDefinitionSerializer threads the owning permission through
- Pin equality semantics to match the batch runtime (default comparer)
Route template used {id} but the method parameter is named blogId, so
ASP.NET Core ApiExplorer emitted an orphan path parameter id, which made
ClientProxyBase.BuildHttpProxyClientProxyContext throw
ArgumentOutOfRangeException when deleting a blog from the MVC admin page.
- Index.cshtml.cs: cache the rendered parameter name set so
IsParameterVisible doesn't allocate a HashSet per call inside the cshtml
loop; clarify per-rule semantics in comments (empty allow-list is an
explicit "never show", null/unknown-key rules fail-open)
- forms-validation.md: drop the inaccurate IValidationRule reference and
describe MudBlazor's actual validation surface (ValidationAttribute on
the Validation parameter, Func<T,string>/Func<T,IEnumerable<string>>,
optional FluentValidation)
- book-store/part-02.md: use {(int)context.Item.Type} for the BookType
localization key to stay consistent with the rest of the tutorial
- Introduce a new "BlazorUI" doc-params dimension (Blazorise / MudBlazor) so
Blazor docs can show MudBlazor variants of code samples next to the existing
Blazorise ones
- Cover framework/ui/blazor (overall, theming, basic-theme, forms-validation,
submit-button, page-layout, page-header, page-toolbar-extensions,
entity-action-extensions, data-table-column-extensions, error-handling,
customization-overriding-components)
- Cover ui-themes (index, basic-theme, lepton-x, lepton-x-lite)
- Cover tutorials (book-store part 02/03/09/10, todo single-layer/layered,
modular-crm part 03/05/06, book-store-with-abp-suite part-05)
- Add an optional "DependsOn" map to DocumentParameterDto so a parameter can
be hidden when dependencies aren't satisfied (e.g. only show BlazorUI when
UI is one of Blazor/BlazorServer/BlazorWebApp). Visibility is evaluated on
the server in the project document index page.
Replaces the TOTP-based Email/Phone 2FA providers under
TokenOptions.DefaultEmailProvider / DefaultPhoneProvider with
DataProtector-backed single-use equivalents.
- Encrypt the 6-digit code via IDataProtector (purpose chain isolated per
provider + token purpose), store ciphertext + absolute UTC expiration
(unix seconds) in the user token table
- Remove the stored entry on successful validation (true single-use)
- Concurrency race (ConcurrencyStamp failure) returns false instead of 500
- Configurable TokenLifespan (default 3 minutes) via Options
AbpSingleActiveTokenProvider.GenerateAsync now checks the IdentityResult
from UserManager.UpdateAsync so a silent persistence failure no longer
returns a token that was not saved.
Related to #25314.
Switching CurrentTenant to user.TenantId in PasswordSignInAsync without refreshing IdentityOptions meant that lockout, password policy and other tenant-scoped options used host values during the base sign-in call. Call IdentityOptions.SetAsync inside the tenant switch so downstream checks use the user's tenant configuration.
- Override IdentityUserManager.FindByIdAsync to fall back to a cross-tenant lookup in shared user sharing strategy so any caller that hits FindByIdAsync from a non-matching tenant context (including base SignInManager internals for TwoFactorSignInAsync and TwoFactorRecoveryCodeSignInAsync) can still resolve a tenant user by id
- Drop the now-redundant AbpSignInManager.GetTwoFactorAuthenticationUserAsync override; the base implementation works automatically through the new FindByIdAsync behavior
- Cover the new FindByIdAsync behavior with unit tests
Guards against regressing the data-access contract behind the 2FA redirect bug: login must find a tenant user by user name from a host context, and the 2FA mid-flow must then resolve the same tenant user by id from the same host context.
Exercises the full cookie round-trip: writes a TwoFactorUserId cookie carrying a tenant user id, then verifies that AbpSignInManager.GetTwoFactorAuthenticationUserAsync returns the tenant user when CurrentTenant is null.
- Add IdentityUserManager.FindSharedUserByIdAsync to resolve a user by id across tenants in shared user sharing strategy
- Override AbpSignInManager.GetTwoFactorAuthenticationUserAsync to use it so the 2FA mid-flow can still find a tenant-scoped user when CurrentTenant is host
- Cover the new method with unit tests
- Replace FormattedStringValueExtracter.Extract with LastIndexOf in
PermissionGrantCacheItem and ResourcePermissionGrantCacheItem to
eliminate repeated string tokenization and object allocations on
every cache key parse (~12,000 calls per request with 4000+ permissions)
- Add fast-path in SimpleStateCheckerManager.InternalIsEnabledAsync to
skip DI scope creation when both StateCheckers and GlobalStateCheckers
are empty, avoiding thousands of unnecessary scope allocations
- Optimize PermissionChecker.IsGrantedAsync(string[]) and
ResourcePermissionChecker.IsGrantedAsync(string[], resourceName, resourceKey)
to load all permission definitions once via GetPermissionsAsync /
GetResourcePermissionsAsync instead of N individual GetOrNullAsync calls,
and use batch StateCheckerManager.IsEnabledAsync for state checking
- Optimize AbpApplicationConfigurationAppService.GetAuthConfigAsync to
pre-load all permission names into a HashSet for O(1) lookup instead
of N async GetOrNullAsync calls inside the loop
- Fix GetResourcePermissionsAsync to deduplicate by (ResourceName, Name)
instead of Name only, matching the actual uniqueness constraint of
resource permissions defined in PermissionDefinitionContext
Production impact (customer with 4000+ permissions): 10s+ -> ~682ms