The log you shared shows ABP Studio backend throwing a NullReferenceException inside the Studio connectivity heartbeat pipeline (IStudioHub/HeartbeatAsync → Volo.Abp.Studio.Connectivity.StudioBackendHub.NotifyHeartbeatAsync). That’s an ABP Studio bug/regression in newer Studio versions (not related to your ABP solution code), and it explains why it “sometimes hangs / crashes while loading projects” and “sometimes crashes when starting containers”.
Since this is a Studio internal exception (and you already confirmed 2.1.4 works while later versions don’t), the only definitive “fix” you can apply locally is:
What to send (so they can reproduce/fix quickly):
~/.abp/studio/ui/logs~/.abp/studio/backend/logs (or any backend/logs under ~/.abp/studio/).abpsln (ABP Studio solution definition) file for that microservice solution (if you can share it), and the approximate project count (you said ~36).Where to report (official channel):
(Links are verified reachable.)
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.
SessionStateService. ABP’s theme language switch uses SessionStateService to get/set the current language, so observing that state is the correct “language changed” signal.import { Injectable } from '@angular/core';
import { SessionStateService } from '@abp/ng.core';
import { distinctUntilChanged, map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class LanguageChangeListenerService {
constructor(private sessionState: SessionStateService) {}
// Emits whenever language changes (e.g. user picks a language from theme UI)
language$ = this.sessionState.getLanguage$().pipe(
distinctUntilChanged()
);
// Example: call some action on change
init() {
this.language$.subscribe(lang => {
// do your action here
// e.g., refresh data, rebuild menus, change moment locale, etc.
console.log('Language changed:', lang);
});
}
}
Then call LanguageChangeListenerService.init() once at app startup (e.g., in AppComponent or an APP_INITIALIZER).
GET /api/abp/application-configuration?includeLocalizationResources=false is called:
HttpInterceptor and watch for that URL.import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable, tap } from 'rxjs';
@Injectable()
export class AppConfigCallInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
tap(() => {
if (req.url.includes('/api/abp/application-configuration')) {
// You can also check req.params for includeLocalizationResources
console.log('ABP application-configuration called:', req.urlWithParams);
}
})
);
}
}
Register it in your module providers:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AppConfigCallInterceptor, multi: true },
]
What service is responsible for calling that API?
SessionStateService.getLanguage$() is the supported way to react to language changes, and an HttpInterceptor is the reliable way to detect calls to /api/abp/application-configuration.https://abp.io/docs/10.1/framework/ui/angular/theming
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.
FileDescriptor + blob content can be created before the main entity is saved. If the user closes the modal / refreshes, those uploaded blobs can remain orphaned unless you add a cleanup strategy.Implement the create/edit form so it does not call the server on file selection. Instead:
CreateAsync(...) and pass the file content as IRemoteStreamContent (or a byte[] if small), then inside the same application service method:
This matches ABP’s general “do it in the application service in a single use-case” style and avoids a “temporary upload” concept entirely.
If you keep the default immediate upload, use a “temporary upload” + scheduled cleanup pattern:
ABP’s Blob Storing API supports deleting blobs, so the cleanup job can safely remove old temporary items.
In the modal’s Cancel/Close handler (and on dispose/navigation), call an endpoint to delete the already-uploaded file descriptor/blob if it hasn’t been finalized. This reduces leftovers but won’t cover hard refresh/tab close/network loss—so you still typically want (B) as the safety net.
Use ABP Blob Storing’s container API to remove orphaned blobs when needed (e.g., in a background worker or explicit cancel endpoint):
public class MyFileCleanupService : ITransientDependency
{
private readonly IBlobContainer<MyFileContainer> _container;
public MyFileCleanupService(IBlobContainer<MyFileContainer> container)
{
_container = container;
}
public Task DeleteAsync(string blobName)
{
return _container.DeleteAsync(blobName);
}
}
You’d combine this with whatever “temporary” tracking you use (DB table/flag, naming convention, etc.) to find candidates to delete.
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, you still need the YARP registration call (whatever your template/module uses, e.g. services.AddYarpReverseProxy() / AddReverseProxy() etc.).
Moving yarp.json content into appsettings.json only changes the configuration source; it does not register YARP services or map the reverse proxy endpoint. If you remove the YARP registration, the gateway won’t actually behave as a reverse proxy (and ABP’s YARP-based swagger aggregation logic won’t behave as expected either).
In the ABP YARP migration guide, the expected change is to change the config loader from Ocelot to YARP:
builder.Host
.AddAppSettingsSecretsJson()
- .AddOcelotJson()
+ .AddYarpJson()
.UseAutofac()
.UseSerilog();
That AddYarpJson() is about loading yarp.json (a separate file). If you merged the content into appsettings.json, you typically don’t need AddYarpJson() anymore, because appsettings.json is already loaded by default. But you still need the YARP service registration and MapReverseProxy().
Why your Swagger suddenly shows “all APIs”:
IProxyConfigProvider and calling options.SwaggerEndpoint(...) for each cluster (see the migration guide’s ConfigureSwaggerUI(proxyConfig, ...) sample). That means if your effective YARP config now contains more clusters than before (because of config merging from multiple sources, or you accidentally broadened routes/clusters), Swagger UI will list more services/APIs.AddAbpSwaggerGenWithOAuth to AddAbpSwaggerGenWithOidc generally affects authentication method in Swagger UI, not which endpoints are included. The “shows all APIs” symptom is much more consistent with the gateway’s swagger endpoints being generated for more clusters (or the proxy now allowing access to more swagger-json endpoints).Definitive setup guidance when ReverseProxy is inside appsettings.json:
ReverseProxy section in appsettings.json.AddYarpJson() (optional) if you deleted yarp.json and don’t want that custom provider anymore.endpoints.MapReverseProxy() (as shown in the migration guide).References (validated):
AddYarpJson(), IProxyConfigProvider-based Swagger endpoints, and MapReverseProxy(): https://abp.io/docs/latest/release-info/migration-guides/pro/migrating-to-yarpappsettings.json / ReverseProxy): https://abp.io/docs/latest/solution-templates/microservice/adding-new-api-gatewaysThis 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.
You didn’t miss anything: in ABP’s microservice gateway setup, Gateway Swagger UI is driven by the gateway’s own Swagger configuration, which (by design) typically points to the swagger-json endpoints that you route through YARP. So what the gateway swagger can “see” depends on what you proxy.
With YARP, ABP’s recommended approach is to define reverse proxy config under the ReverseProxy section (routes/clusters). This can live in appsettings.json (or any configuration source). ABP docs explicitly show configuring YARP via appsettings.json, so moving from yarp.json → appsettings.json is fine as long as the structure is the same.
What to do (definitive):
/swagger-json/Administration/swagger/v1/swagger.json/swagger-json/ProductService/swagger/v1/swagger.json
(each with a PathRemovePrefix transform)
If you add a too-broad route (for example routing /swagger/{**catch-all} or a very generic /{**catch-all}), the gateway swagger UI (or the browser) may be able to resolve more swagger docs than you expect.appsettings.json, appsettings.{Environment}.json, environment variables, configmaps, etc. can merge. If yarp.json is still being loaded somehow (custom code or host builder), you may effectively have more proxy routes/clusters than you think.HideAbpEndpoints() in your swagger setup.Putting YARP config in appsettings.json is supported; the key is keeping your ReverseProxy routes tightly scoped so the gateway swagger can only load the intended swagger documents.
Links (verified):
appsettings.json (ReverseProxy section): https://abp.io/docs/latest/solution-templates/microservice/adding-new-api-gatewaysHideAbpEndpoints): https://abp.io/docs/latest/API/Swagger-Integration#hide-abp-endpoints-on-swagger-uiThis 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 Commercial v10.0.1 guidance (practical + ABP-aligned):
Volo.Abp.Mapperly. This avoids relying on AutoMapper’s runtime recursion behavior entirely.Temporary mitigation via “global MaxDepth in ABP AutoMapper setup”:
Configure<AbpAutoMapperOptions>(...) and an AutoMapper MaxDepth hook) that I can safely recommend here.Which ABP modules/services are affected?
Volo.Abp.AutoMapper + AutoMapper profiles).Volo.Abp.AutoMapper, AddAutoMapperObjectMapper, and Profile : AutoMapper.Profile usage; those are your risk hotspots.Official patch / security timeline request (Commercial-specific):
If you want the ABP-supported replacement path (works on ABP v10):
Volo.Abp.Mapperly.AbpMapperlyModule and register Mapperly object mapper:using Volo.Abp.Modularity;
using Volo.Abp.Mapperly;
[DependsOn(typeof(AbpMapperlyModule))]
public class YourProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMapperlyObjectMapper<YourProjectApplicationModule>();
}
}
(Links you provided: only https://nvd.nist.gov/vuln/detail/CVE-2026-32933 was reachable from my URL validator; the GitHub advisory/OSV links were not reachable at validation time, so I did not rely on them here.)
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.
System.IdentityModel.Tokens.Jwt to 7.5.1Microsoft.IdentityModel.* packages to 7.5.1System.IdentityModel.Tokens.Jwt 6.26.1 is to upgrade your ABP solution to a version that includes these upgraded dependencies (at least ABP 8.2+, and in practice you should move to the latest ABP version in your major line).If you’re staying on ABP 10.1.1 specifically, there is no verified ABP source stating that ABP 10.1.x supports System.IdentityModel.Tokens.Jwt 8.x via its own packages. The verified ABP guidance available shows the framework moving to 7.5.1 (not 8.x) as part of its dependency upgrades.
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.
_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/.../font-bundle.css (it comes from the NuGet package and will be regenerated/overwritten).font-bundle.css with your own file (same virtual path) so the @import url("https://fonts.googleapis.com/...") line is never shipped to the browser.MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.css
Put your local @font-face declarations there (pointing to your local .woff2/.woff files under wwwroot/fonts/inter/...) and do not include any @import to Google Fonts.
Example skeleton (adjust paths to your real files):
/* MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.css */
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("/fonts/inter/Inter-VariableFont.woff2") format("woff2");
}
/* add italic, opsz variants as needed... */
MyProjectBlazorClient/wwwroot/_content/Volo.Abp.AspNetCore.Components.Web.LeptonXTheme/side-menu/css/font-bundle.rtl.css
(Usually it can be identical to font-bundle.css.)
font-bundle.css, but it will now be served from your app and will not contain the Google Fonts import, so no request to fonts.googleapis.com will be triggered.This works because ABP serves static files from your app’s wwwroot, and a file placed under the exact same _content/{packageId}/... path effectively overrides the packaged static resource at runtime.
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.
/Account/ForgotPassword UI does not include a reCAPTCHA challenge by default. That’s why you can toggle it for login/registration but don’t see an option for the forgotten password page./Account/ForgotPassword (same way you customize Login/Register pages in ABP: copy the page into your host project under Pages/Account so it overrides the module page).ForgotPassword.cshtml, render your CAPTCHA widget (Google reCAPTCHA or any other).ForgotPassword.cshtml.cs, validate the CAPTCHA before calling the underlying password reset flow. If CAPTCHA fails, return the page with an error message and do not send the email.SendPasswordResetCodeAsync on AccountAppService via service replacement:[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IAccountAppService))]
public class MyAccountAppService : AccountAppService
{
public MyAccountAppService(/* same ctor deps as base */) : base(/* ... */)
{
}
public override async Task SendPasswordResetCodeAsync(SendPasswordResetCodeDto input)
{
// 1) Rate limit / throttle here (per IP/email/etc.)
// 2) Optionally perform extra checks
// 3) Then call base or replicate base logic
await base.SendPasswordResetCodeAsync(input);
}
}
Add your throttling logic before calling base.SendPasswordResetCodeAsync(input).
If you implement (1), you stop most automated attacks at the UI level. If you implement (2), you protect the system even if attackers bypass the UI and call the endpoint directly.
Links:
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.
DateTime value coming from the database is UTC (which is the typical/recommended setup when AbpClockOptions.Kind = DateTimeKind.Utc), then to get it in the configured timezone (app/tenant/user via Abp.Timing.TimeZone, e.g. EST), call:var estTime = Clock.ConvertToUserTime(utcDateTime);
Example (entity loaded from DB):
var entity = await _repo.GetAsync(id);
// entity.SomeTime is assumed UTC
var estTime = Clock.ConvertToUserTime(entity.SomeTime);
Notes (important):
ConvertToUserTime(DateTime dateTime) only converts if:
AbpClockOptions.Kind = DateTimeKind.Utc so IClock.SupportsMultipleTimezone == true), anddateTime.Kind is Utc.DateTime will have Kind = Unspecified (as shown in ABP’s examples), because it represents “user/local” time without embedding timezone in DateTime.If you are using DateTimeOffset properties, you can also use:
var estTimeOffset = Clock.ConvertToUserTime(dateTimeOffset);
Sources:
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.