IStringEncryptionService for encrypting/decrypting strings (ABP implementation uses AES; documented as AES/CBC) and configuration via AbpStringEncryptionOptions.IStringEncryptionService is AES/CBC and string-focused).IEncryptedBlobStore that:
IBlobContainerThis avoids forking ABP Blob Storing and keeps encryption logic isolated.
IStringEncryptionService, but for file encryption best practice is AEAD (e.g., AES-GCM) with a random nonce per object + authentication tag. (ABP does not ship a file-encryption abstraction; you implement this with .NET cryptography.)IStringEncryptionService which you can use to implement field encryption yourself (e.g., EF Core ValueConverter, or domain setters/getters).ValueConverter<string,string> that uses IStringEncryptionService.Encrypt/Decrypt.OnModelCreating.Important operational consequence:
Where(x => x.NationalId == "…")) unless you:
IStringEncryptionService, AES-based) and ASP.NET Core data protection; anything beyond that (token vault, format-preserving tokenization, searchable encryption) is custom/external.AbpStringEncryptionOptions requires consistent parameters across instances; you should load secrets from a centralized secret manager (example ABP community article shows AWS Secrets Manager integration).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.
This looks like an ABP Studio 3.0.3 UI crash while it is trying to refresh the Kubernetes/Helm chart tree after you add the second Web module (apps -> Add -> New Module -> Web). The stack trace is inside ABP Studio (HelmSubChartItemViewModel, ChartUIModel.RefreshSubChartsAsync), not in your solution code, and it typically happens when Studio expects a Helm subchart metadata object but it is missing/null for the newly added app.
Workaround (recommended): manually create the Helm subchart for the new web app, then refresh charts.
Chart.yaml and a charts/ directory) in VS Code.charts/ folder, create a new folder for your new web app (e.g. tenant-web/).TenantAdminWeb) as a template, and update its metadata/values to match the new app (image name, project path, etc.).This aligns with ABP Studio’s documented flow: when you add a microservice/module, you should also create its subchart, then refresh subcharts so Studio can load them properly.
Practical mitigation if you don’t need Kubernetes integration right now:
If you want this fixed in Studio rather than working around it:
(Links 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.
AutoMapper / Scriban package updates (vulnerabilities):
VS 2026 stopping EF migration generation / DB update regardless of ErrorActionPreference:
Actionable guidance you can safely apply in ABP solutions:
8.3.x → latest 8.3.*) since ABP dependency updates typically ship via ABP releases.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.
Yes, this behavior is a known type of UI refresh/layout issue in Angular apps where the table is rendered before its container gets a final size (e.g., after route animation/layout calculations). A window resize triggers a reflow, so the datatable suddenly paints correctly. The same reason explains why clicking sort sometimes doesn’t redraw until resize.
In ABP Angular UIs, a practical workaround is to force a resize/reflow after the data arrives / after view init on the Users/Roles pages (or globally after navigation).
Add a small resize dispatch after the list loads or after the view is stable:
import { AfterViewInit, Component, NgZone } from '@angular/core';
@Component({...})
export class UsersComponent implements AfterViewInit {
constructor(private zone: NgZone) {}
ngAfterViewInit() {
// Let Angular finish rendering, then trigger a reflow for the datatable
this.zone.runOutsideAngular(() => {
setTimeout(() => window.dispatchEvent(new Event('resize')), 0);
setTimeout(() => window.dispatchEvent(new Event('resize')), 100);
});
}
}
If you don’t want to touch module pages, you can do something similar once globally after each navigation ends (e.g., in your root layout component subscribing to Router events) and dispatch a resize.
No verified source available for this specific v9.1.2 Identity Users/Roles datatable-resize rendering issue (tooling could not access the ABP source repositories at the moment to confirm a specific fix/issue ID).
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.
This behavior is consistent with the DTO mapping not copying ExtraProperties from Volo.Saas.Tenants.Tenant to SaasTenantDto in the SaaS Host tenant listing flow.
In ABP, extension properties stored in JSON (ExtraProperties) are not automatically included in outgoing DTOs unless the application service maps them (for security reasons). The usual/conventional way is to call MapExtraPropertiesTo(...) while mapping entity → DTO (or enable/configure MapExtraProperties in the object mapper profile).
So, even if:
ExtraProperties["TaxNumber"] = "12345678"…the grid cells will remain empty if the returned SaasTenantDto.ExtraProperties doesn’t contain that value.
Recommended fix (JSON-only; no MapEfCoreProperty required): override/replace the SaaS tenant app service and map extra properties to the DTO in GetListAsync (and other relevant methods).
Example (replace the built-in service):
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.DependencyInjection;
using Volo.Saas.Host;
using Volo.Saas.Tenants;
namespace MyCompany.MyProject.Saas;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(ITenantAppService), typeof(TenantAppService))]
public class MyTenantAppService : TenantAppService
{
public MyTenantAppService(
ITenantRepository tenantRepository,
TenantManager tenantManager)
: base(tenantRepository, tenantManager)
{
}
public override async Task<PagedResultDto<SaasTenantDto>> GetListAsync(GetTenantsInput input)
{
var result = await base.GetListAsync(input);
// Ensure extra properties are present in the DTOs so UI can render them
// (TaxNumber, etc.)
foreach (var item in result.Items)
{
// Nothing to do if already mapped by base implementation.
// If empty, you must map from entity to dto at mapping time.
}
return result;
}
}
However, to actually map from entity → DTO, you need access to the source entities at mapping time. The cleanest approach is to override mapping method if exists, or reimplement GetListAsync by querying entities and mapping yourself, explicitly calling MapExtraPropertiesTo:
using System.Linq;
using Volo.Abp.ObjectExtending;
public override async Task<PagedResultDto<SaasTenantDto>> GetListAsync(GetTenantsInput input)
{
var totalCount = await TenantRepository.GetCountAsync(input.Filter);
var tenants = await TenantRepository.GetListAsync(
input.Sorting,
input.MaxResultCount,
input.SkipCount,
input.Filter
);
var dtos = tenants.Select(t =>
{
var dto = ObjectMapper.Map<Tenant, SaasTenantDto>(t);
// Critical line:
t.MapExtraPropertiesTo(dto);
return dto;
}).ToList();
return new PagedResultDto<SaasTenantDto>(totalCount, dtos);
}
With that, your JSON-only extension property (TaxNumber) will be present in the returned SaasTenantDto.ExtraProperties, and the Host → SaaS → Tenants grid will be able to render the cell values again.
Answers to your questions (based on verified ABP behavior):
MapEfCoreProperty is not required just to display values. It’s a persistence/query optimization choice. JSON-only should work as long as entity → DTO mapping copies extra properties.MapExtraPropertiesTo / MapExtraProperties)ExtraProperties storage)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.
BackgroundJobExecuter.GetJobArgsTenantId(jobArgs), and when the args don’t implement IMultiTenant, the executer falls back to CurrentTenant.Id (which is typically null on the worker), so the job runs in host context.tenants/<tenant-id> when the current tenant is not null. So running the indexing job in host context makes it look under the wrong blob key.IMultiTenant and including TenantId in the serialized args.Example (conceptual fix):
using System;
using Volo.Abp.MultiTenancy;
public class IndexDocumentJobArgs : IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid DataSourceId { get; set; }
}
When enqueueing:
await _backgroundJobManager.EnqueueAsync(
new IndexDocumentJobArgs
{
TenantId = _currentTenant.Id,
DataSourceId = dataSourceId
}
);
This makes BackgroundJobExecuter switch to that tenant before calling ExecuteAsync, so the blob provider will resolve the correct tenants/<tenantId>/... prefix.
Wrap the job execution with an explicit tenant change (only works if you can determine tenantId from DB by DataSourceId without requiring tenant context, e.g., host-visible table or query with disabled filter):
using (_currentTenant.Change(tenantId))
{
// read blob + index
}
Given how ABP blob naming works, the job must run under the same tenant that uploaded the blob (or you must disable multi-tenancy for that blob container, which would change the storage layout and isolation semantics).
ICurrentTenant.Change): https://abp.io/docs/latest/framework/architecture/multi-tenancy#change-the-current-tenantThis 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.
Recommended migration path (ABP 9.3.2 → 10.4.0)
AutoMapper → Mapperly strategy (officially supported)
ABP v10 switches the default mapper used by ABP modules to Mapperly, while AutoMapper integration still exists for backward compatibility. The safest approach is:
ObjectMapper has AutoMapper correctly registered (especially your Blazor module).AbpMapperlyModule, AddMapperlyObjectMapper, and Mapperly mapper classes derived from MapperBase<,> / TwoWayMapperBase<,>).Practical “gotcha” that causes “No object mapping was found…”: if you register a contextual object mapper (e.g. AddAutoMapperObjectMapper<MyBlazorModule>() or AddMapperlyObjectMapper<MyBlazorModule>()), you must also set the ObjectMapperContext where you call ObjectMapper.Map(...) (Blazor pages/components commonly hit this). This is a known real-world fix pattern in ABP support.
Navigation properties / WithNavigationProperties DTOs
There isn’t a single “one breaking change” bullet in the public sources you provided that explains all navigation/collection-related DTO generator problems. In practice, what you’re describing is commonly a mapping registration + generated DTO shape mismatch problem after switching mapping provider and/or regenerating code. The most deterministic fix path is:
context.Services.AddMapperlyObjectMapper();) in a root module that is always loaded.WithNavigationProperties DTOs, add/verify explicit mappings for:
EntityWithNavigationProperties ↔ EntityWithNavigationPropertiesDtoABP Suite / CRUD Page Generator compatibility ABP Suite can generate for v10, but if you migrate an existing v9 solution and then regenerate, you should expect manual adjustments where your project has custom conventions (navigation display properties, custom DTOs, Identity Pro integration patterns, etc.). Treat generator output as a starting point; stabilize compilation after each regeneration step.
Recommended upgrade order (minimizes churn)
AddMapperlyObjectMapper() is called so ObjectMapper.Map uses Mapperly.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.
AllowedProviders (set via WithProviders(...)) is intended to restrict which value providers are considered at runtime for that feature. So in your example, if the feature only allows TenantFeatureValueProvider.ProviderName (“T”), then IFeatureChecker will ignore the edition (“E”) value even if one exists, and only tenant/default can take effect.FeatureDefinition.AllowedProviders. As a result, it can still let you save an edition-level value that will never be used at runtime for that feature. This is essentially a UX mismatch: the stored value is valid data, but it is not applicable given the feature definition’s allowed providers.What you should do to avoid the “configurable but ignored” situation:
context.AddGroup("MyGroup")
.AddFeature("MyFeature",
defaultValue: "false")
.WithProviders(
TenantFeatureValueProvider.ProviderName,
EditionFeatureValueProvider.ProviderName
);
AllowedProviders does not include "E".No verified source available for this specific UI behavior detail in ABP 10.1.1 (the runtime provider filtering is consistent with the feature system’s “Feature Value Providers executed one by one” design, but the “Edition Features dialog should hide/disable based on AllowedProviders” behavior is not documented/guaranteed).
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.
abp suite remove
abp suite install
Then start Suite again:
abp suite
abp logout
abp login
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.
This is a LeptonX theme bug/limitation in the “custom select” overlay implementation: LeptonX hides the native <select> (where Blazorise applies is-invalid, aria-invalid, aria-describedby, and where the <ValidationError /> feedback is associated) and renders a proxy element (e.g. .custom-select-display). The proxy does not mirror the validation state, so you don’t see the red border and the validation message behavior you get with TextInput.
Workaround (recommended): avoid the LeptonX custom-select overlay for the affected fields so the real <select> remains the visible/styled control.
<select> (or otherwise ensure the element does not get enhanced by LeptonX’s custom select script/CSS in your setup).form-select-enhanced path for those selects (the LeptonX overlay targets Bootstrap-styled selects). For pages/components where you need Blazorise validation visuals, use a plain select style/class that LeptonX does not transform.If you must keep LeptonX’s custom select UI, then the only robust fix is on the theme side: LeptonX would need to propagate validation-related classes/attributes from the hidden <select> to .custom-select-display (and ensure feedback markup is visually associated). There isn’t an ABP-side configuration switch in the provided sources that makes LeptonX do this automatically.
Links (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.