docs/en/release-info/migration-guides/abp-10-4.md
//[doc-seo]
{
"Description": "Upgrade your ABP solutions from v10.3 to v10.4 with this migration guide covering important behavior and integration changes."
}
This document is a guide for upgrading ABP v10.3 solutions to ABP v10.4. There are no explicitly marked breaking changes in this release scope, but there are some important changes that may require action in specific application scenarios.
Package Version Changes: Before upgrading, review the Package Version Changes document to see version changes on dependent NuGet packages and align your project with ABP's internal package versions.
This version contains the following changes on the open-source side:
Who is affected
What changed
/en/products or /tr/identity/users.What to do
If you do not enable URL-based localization, no action is required.
If you enable it, configure AbpRequestLocalizationOptions:
Configure<AbpRequestLocalizationOptions>(options =>
{
options.UseRouteBasedCulture = true;
});
For custom Blazor pages, add culture route variants:
@page "/Products"
@page "/{culture}/Products"
For Angular applications, wrap your route tree with withOptionalRouteCulturePrefix from @abp/ng.core, and use the route-culture URL helpers/pipes for menu links, breadcrumbs, and language switching.
See the URL-Based Localization document and #25174 for details.
Who is affected
What changed
culture value under the same localization resource.What to do
No action is required for existing applications.
If you split localization files, choose deterministic file names and avoid unintended duplicate keys:
Localization/
+-- MyResource/
+-- en.json
+-- en_Authors.json
+-- en_Books.json
See #25227 for details.
Who is affected
What changed
UserManager.GenerateChangePhoneNumberTokenAsync / VerifyChangePhoneNumberTokenAsync also inherit the new stored-token semantics because ASP.NET Core Identity uses the default phone provider for phone-number changes.What to do
Configure<AbpEmailTwoFactorTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromMinutes(5);
options.CodeLength = 8;
});
Configure<AbpPhoneNumberTwoFactorTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromMinutes(2);
});
TokenOptions.DefaultEmailProvider and/or TokenOptions.DefaultPhoneProvider.See the Two Factor Authentication document and #25316 for details.
Who is affected
What changed
What to do
See #25235 for details.
IsSandboxed MarkerWho is affected
Volo.Abp.TextTemplating.ITemplateRenderingEngine directly (not deriving from TemplateRenderingEngineBase).What changed
ITemplateRenderingEngine exposes a new required property:
bool IsSandboxed { get; }
Sandboxed engines (e.g. Scriban) interpret templates as a restricted DSL without .NET interop. Non-sandboxed engines (e.g. Razor) compile templates into fully-trusted .NET code that runs with the same privileges as the host process.
TemplateRenderingEngineBase provides a virtual default of false (secure-by-default): engines that derive from the base class and don't override the property are treated as non-sandboxed.
RazorTemplateRenderingEngine declares IsSandboxed => false (compiles to .NET assembly via Roslyn).
ScribanTemplateRenderingEngine declares IsSandboxed => true and now sets Scriban's TemplateContext.MemberFilter so only public properties on imported objects are exposed; methods, fields, events and reflection entry points (GetType, Assembly, ...) are no longer reachable from Scriban templates.
What to do
If your application registers a custom engine by implementing ITemplateRenderingEngine directly (without deriving from TemplateRenderingEngineBase), add the property:
public bool IsSandboxed => false; // or true if your engine cannot execute host code
If your engine derives from TemplateRenderingEngineBase, no action is required for compilation; however, override IsSandboxed => true if your engine is genuinely sandboxed so callers (such as the Text Template Management module) treat its templates as safe to edit by non-developer users.
Scriban templates that invoke methods on the model (e.g. {%{{{ model.SomeMethod }}}%}) or read fields stop working because the engine now whitelists public properties only. Templates that access only properties (the typical Scriban usage) are unaffected. To restore the previous behavior in custom hosts, derive from ScribanTemplateRenderingEngine and override IsMemberAllowed to allow methods or fields:
protected override bool IsMemberAllowed(MemberInfo member) => true;
Only do this when the model objects are trusted and do not carry secrets, since the previous behavior exposed reflection entry points (GetType, Assembly, ...) on imported .NET objects.
See #25399 for details.
EditContents Permission Split (security)Who is affected
TextTemplateManagement.TextTemplates.EditContents permission to roles that are not fully trusted server administrators/developers.Volo.Abp.TextTemplating.Razor) and have any non-developer role with EditContents.What changed
TextTemplateManagement.TextTemplates.EditNonSandboxedContents has been added.ITemplateRenderingEngine.IsSandboxed == false, e.g. Razor) now requires both permissions: EditContents and EditNonSandboxedContents.admin role. The previously implicit assumption — that EditContents was enough to edit Razor templates — has been corrected: editing such templates is functionally equivalent to granting server-side code execution and is now gated by an explicit permission whose name communicates that risk.What to do
After upgrading, audit which roles currently hold EditContents and decide which of them should also be granted EditNonSandboxedContents:
Roles that should only edit sandboxed templates (e.g. Scriban, Liquid, plain HTML) need no further action — they keep editing those templates.
Roles that need to continue editing Razor templates must be granted EditNonSandboxedContents explicitly via the Permission Management page.
If — and only if — you have reviewed your role assignments and confirmed that every role currently holding EditContents is trusted to execute server-side code through Razor templates, you may seed the new permission for those roles via your IDataSeedContributor:
var grants = await _permissionGrantRepository.GetListAsync(
TextTemplateManagementPermissions.TextTemplates.EditContents);
foreach (var grant in grants)
{
await _permissionManager.SetAsync(
TextTemplateManagementPermissions.TextTemplates.EditNonSandboxedContents,
grant.ProviderName,
grant.ProviderKey,
isGranted: true);
}
Do not automate this seeding for arbitrary tenants/roles without first reviewing the current grants — auto-restoring the previously-implicit elevated trust would defeat the security improvement. The recommended path is to grant the new permission only to specific developer/operator roles via the Permission Management UI.
If your application's data seeder grants all permissions in the TextTemplateManagement group to a role (e.g. the admin role), that role will automatically receive EditNonSandboxedContents on first run after upgrade. Audit your seeder if you want stricter defaults.
See the Razor Integration document and #25399 for details.
Who is affected
What changed
System.Security.Cryptography.Xml was upgraded to 10.0.6.What to do
There are no explicitly marked breaking changes on the PRO side in this release scope. However, check the following if they apply to your application.
Who is affected
What changed
What to do
PreventEmailEnumeration behavior.Who is affected
What changed
What to do
Who is affected
What changed
stdio transport scenarios and workspace relationships.What to do
Who is affected
What changed
What to do