- ABP Framework version: v10.5.0 (
Volo.Abp.AdminConsole10.5.0) - UI Type: React
- Database System: EF Core (SQL Server)
- Tiered (for MVC) or Auth Server Separated (for Angular): no — single host (API + OpenIddict auth server)
- Exception message and full stack trace: none. There is no exception; the failure is silent. The Admin Console returns HTTP 200 and renders a blank page, with 404s for its assets in the browser network log.
- Steps to reproduce the issue: below.
Summary
When the host runs under a non-root PathBase, the Admin Console routes correctly but serves a shell whose <base href> and asset URLs omit the PathBase. The browser therefore requests the assets from the site root, they 404, and the console renders as a blank page.
We hit this deploying to an IIS virtual application, where IIS sets Request.PathBase at the server layer. It applies equally to any reverse-proxy sub-path deployment.
Steps to reproduce
- Create an ABP 10.5.0 React solution whose host references
AbpAdminConsoleModule, withAdminConsole:IsEnabled=true. - In
Program.cs, addapp.UsePathBase("/sub");immediately beforeawait app.InitializeApplicationAsync();. This puts thePathBasein the same position IIS in-process hosting does. - Run the host and request
GET /sub/admin-console. - Observe HTTP 200, then inspect the response body: its
<base href>is/admin-console/, and every asset URL is root-absolute, none carrying/sub. - Load
/sub/admin-consolein a browser: the page is blank and every asset request 404s.
Deploying the same host as an IIS virtual application at /sub (in-process) reproduces it with no code change at all.
The defect can also be confirmed without deploying anything, because the shell is a static file shipped in the package. This prints it in full:
$dll = "$env:USERPROFILE\.nuget\packages\volo.abp.adminconsole\10.5.0\lib\net10.0\Volo.Abp.AdminConsole.dll"
$asm = [System.Reflection.Assembly]::LoadFrom($dll)
$s = New-Object System.IO.StreamReader(
$asm.GetManifestResourceStream('Volo.Abp.AdminConsole.wwwroot.admin_console.index.html'))
$s.ReadToEnd()
Expected behaviour
The Admin Console honours Request.PathBase in its <base href> and asset URLs, so it works when the host is deployed under a virtual application or reverse-proxy sub-path. Under a PathBase of /sub, the shell's <base href> should be /sub/admin-console/, with asset URLs that resolve correctly beneath it.
Actual behaviour
<base href> and all asset URLs are emitted root-absolute, so the Admin Console is unusable under any non-root PathBase.
Root cause
The shell is not rendered at request time. It is a static file embedded in the shipped assembly — Volo.Abp.AdminConsole.wwwroot.admin_console.index.html, 948 bytes, registered through ABP's Virtual File System and served by AdminConsoleSpaMiddleware — with /admin-console/ written into it as a literal at your build time.
I would have pasted that file here, but this forum's security filter rejects posts carrying a page's worth of markup, so here it is transcribed instead. The PowerShell above prints the byte-exact original if you want to check the transcription. Its <head> holds exactly these eight references, in this order — tag, then attributes, then URL:
| # | tag | attributes | URL |
| --- | --- | ---------- | --- |
| 1 | base | — | /admin-console/ |
| 2 | link | rel="icon" type="image/svg+xml" | /admin-console/favicon.svg |
| 3 | script | type="module" crossorigin | /admin-console/assets/index-CVgBU-QA.js |
| 4 | link | rel="modulepreload" crossorigin | /admin-console/assets/rolldown-runtime-S-ySWqyJ.js |
| 5 | link | rel="modulepreload" crossorigin | /admin-console/assets/vendor-query-Drt5MjtQ.js |
| 6 | link | rel="modulepreload" crossorigin | /admin-console/assets/vendor-react-Deby2yrZ.js |
| 7 | link | rel="modulepreload" crossorigin | /admin-console/assets/vendor-router-DR8po1Y7.js |
| 8 | link | rel="stylesheet" crossorigin | /admin-console/assets/index-C6allXm8.css |
Besides those, the <head> carries only charset and viewport meta tags and the title Admin Console; the <body> is a single empty div with id="root". Nothing else.
So: eight root-absolute, PathBase-free URLs — the <base href>, the favicon, the entry script, four modulepreload links, and the stylesheet.
Because nothing renders this file per request, no runtime configuration can correct it — which is why the options below do not help.
For contrast, Swagger UI in the same host is unaffected under the same PathBase, because it emits relative references (./swagger-ui.css, ./swagger-ui-bundle.js) that resolve against the current URL.
Configuration we checked first
AbpAdminConsoleOptions declares twelve properties, read directly from the shipped assembly's metadata:
IsEnabled, RedirectRootToAdminConsole, Authority, AuthServerApplicationUrl, ClientId, Scope, ThemeOverrideCssPath, ApplicationName, LogoUrl, InitialTheme, CustomizationPermissionName, LocalizationLanguages.
None of them is a base path or route prefix, and no other type in the assembly declares one. We also found nothing in the Admin Console documentation describing sub-path or reverse-proxy hosting.
Other workarounds considered, and why they are inadequate
- A server-level URL rewrite mapping
/admin-console/*into the virtual application rescues exactly one deployment. Two environments of the same application on one site — for us, Staging and Demo — collide on the same root-level prefix, so it cannot work in general. - Patching the packaged SPA is not viable: the paths are baked into the published assets inside the NuGet package.
What we are doing instead
We wrote response-rewriting middleware in our own host that prefixes every root-absolute href/src in the shell with Request.PathBase. It works, verified against 10.5.0, but it is a workaround rather than a fix: we are rewriting your HTML on the way out, and it will break silently if the shell is restructured. We would prefer to delete it.
Suggested fix
Because the shell is pre-built, the fix belongs at build or serve time. Two changes would do it, and they compose:
- Build the Admin Console bundle with a relative base, so emitted asset references are relative (
assets/index-*.js) rather than root-absolute (/admin-console/assets/index-*.js). They then resolve against whatever<base href>is in effect, collapsing eight URLs into one value that has to be correct. - Substitute
<base href>when the file is served. With (1) in place this is the only request-dependent value left, andAdminConsoleSpaMiddlewarealready owns the response — a placeholder token replaced on the way out, or a cached transformed copy, would be enough. The SPA router's basename can then be read fromdocument.baseURIinstead of being fixed at build time.
Either half alone is an improvement: (1) makes the problem tractable for consumers who can set a base, and (2) fixes it outright.
One other thing
The UI section of this form's question details form doesn't include React as an option.
3 Answer(s)
-
0
In ABP 10.5.0, the Admin Console SPA is shipped as pre-built static assets (embedded via the Virtual File System and served by
AdminConsoleSpaMiddleware) and is hosted under/admin-console/*. Because the shippedindex.htmlcontains root-absolute URLs (e.g.href="/admin-console/...",src="/admin-console/...") they won’t automatically includeRequest.PathBasewhen your app is hosted under a sub-path (IIS virtual application, reverse proxy path prefix,app.UsePathBase("/sub"), etc.). Your analysis of the failure mode is correct.There is no runtime option in
AbpAdminConsoleOptionsto set a base path / path base, so you cannot fix this purely with configuration.Practical workaround (server-side, non-invasive to the NuGet package): keep your response-rewriting (or equivalent) but do it in a way that is tightly scoped and resilient:
- Only target the Admin Console shell request (the SPA fallback
index.html), not all responses. - Rewrite:
<base href="/admin-console/">to<base href="{Request.PathBase}/admin-console/">- any
href="/admin-console/.../src="/admin-console/...to be prefixed withRequest.PathBase
- Cache the rewritten HTML per
PathBasevalue (usually there’s only one in a deployment).
This is the only host-level workaround that keeps using the packaged SPA as-is.
- Only target the Admin Console shell request (the SPA fallback
If you can change deployment topology: the other workaround is to ensure the reverse proxy/IIS doesn’t mount the app under a PathBase (i.e., make the app the site root), but you already explained why that’s often not possible.
Suggested product fix (what you proposed is aligned with the underlying issue):
- Build the Admin Console bundle so assets are relative (or otherwise PathBase-aware).
- Or have
AdminConsoleSpaMiddlewareinjectPathBaseat response time (e.g., placeholder token replacement for the<base href>and/or asset URLs).
No verified source available that documents a built-in setting or officially supported approach for hosting the embedded Admin Console under a non-root
PathBasein 10.5.x.- https://abp.io/docs/10.5/framework/ui/react/admin-console
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.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
This is a bug report, not a request for a workaround. It seems that while PathBase is a supported configuration, ABP never tests with PathBase set to anything other than root. In a previous Blazor Server project, I ended up filing multiple PathBase bug reports, which were ultimately fixed. I can't control the infrastructure my projects have to work with; creating new domains or subdomains for each project would require months of approval bureaucracy and slow work to a crawl, leaving my only option to install in a subdirectory of an existing domain.
My recommendation is that for each supported frontend type ABP add some tests with PathBase set to a subdirectory which exercise URL generation across all UI surfaces.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
You're right, this is a bug. The Admin Console shell is pre-built with root-absolute
/admin-console/...URLs and the middleware serves it as-is, so it can't work under a non-rootPathBase, and there is no configuration in 10.5.0 that can change it.Your response-rewriting middleware is a reasonable interim solution, but it covers the shell only. The SPA bundle also resolves the default API base to the root-absolute
/api, and its router basename is fixed at build time. Withapp.UsePathBase("/sub")locally this doesn't show up, because requests without the/subprefix are still answered by the same app — but in a real IIS virtual application, the module API calls (Identity, Settings, etc.) go to the site root. Worth double-checking those pages in your Staging/Demo deployments.We're preparing a fix along the lines you suggested: the middleware will prefix the
<base href>and asset URLs withRequest.PathBasewhen serving the shell, the config endpoint will return a PathBase-aware authority and application root, and the SPA will derive its router basename and API base at runtime instead of baking them in at build time. Once it's released you can delete your middleware; we'll post the version here when it's confirmed.Your ticket has been refunded. And thanks for the note about the missing React option in the question form — we'll forward it to the team.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)