AbpAspNetCoreMvcOptions and calling options.ConventionalControllers.Create(...).PreConfigureServices method of your *.WebModule (or *.HttpApiHostModule).using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
[DependsOn(typeof(MyProjectApplicationModule))]
public class MyProjectWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(MyProjectApplicationModule).Assembly);
});
}
}
Notes:
Use the Application assembly (where your AppServices are) in Create(...) so ABP can generate API controllers for those application services.
If you’re in a tiered solution, you typically put this in HttpApi.Host (not the MVC UI project), because that’s where the APIs are exposed.
https://abp.io/docs/latest/framework/api-development/auto-controllers
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.
In your Web project Program.cs (or the equivalent in your ABP host), ensure you have endpoint routing and map controller routes:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseConfiguredEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// If you want to prevent Razor Pages endpoints from being reachable,
// do NOT map Razor Pages:
// endpoints.MapRazorPages();
});
If your solution currently maps Razor Pages somewhere (some templates do), removing MapRazorPages() will stop Razor Page endpoints from being matched.
If you want ABP to automatically expose your Application Services as HTTP APIs (common when building controller/view UIs that call backend APIs), make sure conventional controllers are enabled:
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers.Create(typeof(MyProjectApplicationModule).Assembly);
});
This is especially relevant in “public web” style setups where proxies/controllers may not be created by default.
Once the endpoints are mapped, the rest of the “conversion” is purely at the feature level:
Pages/... Razor Pages with Controllers/...Controller.csViews/.../*.cshtmlasp-page="..." to asp-controller / asp-actionThis 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.
Pages/*.cshtml endpoints and implement the same endpoints as Controllers/*Controller.cs + Views/*/*.cshtml (while keeping ABP’s theme/bundling/layout infrastructure).Leave all ABP modules, authentication (AuthServer/OpenIddict), localization, theming, etc. intact.
For each UI feature currently implemented as Razor Pages:
Pages/Foo/Index.cshtml (+ Index.cshtml.cs)Pages/Foo/Create.cshtml (+ Create.cshtml.cs)Pages/Foo/Edit.cshtml (+ Edit.cshtml.cs)You will create:
Controllers/FooController.csViews/Foo/Index.cshtmlViews/Foo/Create.cshtmlViews/Foo/Edit.cshtmlOnce the controller routes work, you can delete (or ignore) the old Razor Pages under Pages/ to avoid duplicate endpoints.
Razor Page
/BooksPages/Books/Index.cshtml and Pages/Books/Index.cshtml.csMVC
/BooksControllers/BooksController.cs and Views/Books/Index.cshtmlusing Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace MyCompany.MyProject.Web.Controllers;
[Route("[controller]")]
public class BooksController : AbpController
{
[HttpGet]
[Route("")]
public IActionResult Index()
{
return View();
}
[HttpGet]
[Route("Create")]
public IActionResult Create()
{
return View();
}
}
Key ABP point: keep your business logic in Application Services (e.g., IBookAppService). Your controller should call application services and pass view models to views.
asp-page usages with MVC equivalentsIn ABP Razor Pages UIs, you often see:
asp-page="/Books/CreateModal"Url.Page(...)When you move to controllers:
asp-controller="Books" asp-action="Create" or Url.Action(...).Example:
<a class="btn btn-primary" asp-controller="Books" asp-action="Create">New Book</a>
ABP templates commonly use “CreateModal / EditModal” Razor Pages (opened via JS modal manager). If you want controller-based pages, a proven approach is to turn those modals into normal pages (and then you can further convert to controllers if you want).
A community article shows exactly how to convert ABP modal pages into regular pages by:
(Use the technique/pattern, then you can translate the endpoint from Razor Page to MVC Controller.)
This reference includes a working commit you can follow.
Even when you move to controllers+views, ABP’s theming/bundling still applies.
(You’ll typically override Themes/.../Layouts/... and configure AbpBundlingOptions to add your CSS/JS.)
Once your controller routes are ready:
Pages/... files, or at least ensure you’re not linking to them anymore.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.
Volo.* NuGet packages and module dependencies (example below).abp new MyCompany.MyProject --ui mvc --database-provider ef
*.DbMigrator (and host/web if needed), then run the migrator to create DB + seed admin user.If you already have an ABP MVC solution and want to add a commercial module manually (without abp add-module), the general steps are:
DependsOn(...) attribute of your module classes.builder.ConfigureXxx() inside your DbContext.OnModelCreating.Example (from the official “File Management Module (Pro) – Manual Installation” approach):
*.Application.csproj):<PackageReference Include="Volo.FileManagement.Application" Version="x.x.x" />
*.ApplicationModule):[DependsOn(
// ...
typeof(FileManagementApplicationModule)
)]
public class MyProjectApplicationModule : AbpModule
{
}
DbContext:protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureFileManagement();
}
package.json (Web project):"dependencies": {
"@volo/file-management": "^2.9.0"
}
abp install-libs
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. ABP automatically applies Unit of Work (UOW) to all public application service methods by convention, regardless of whether the method is “Get”/read-like or “Create/Update/Delete”. So your Get... method is inside a UOW scope too.
However, being inside a UOW doesn’t always mean a DB transaction is started. With the default UnitOfWorkTransactionBehavior.Auto behavior for HTTP requests, GET HTTP requests don’t start a transactional UOW by default. That said, you can still write to the database inside a GET method, and it can still cause locks/contention and timeouts (especially if that GET endpoint is hit frequently).
What you should do in your case (since your GET calls UpdateAsync)
[UnitOfWork(IsDisabled = true)]
public virtual async Task<AgentDto> GetAsync(Guid id)
{
// read-only code only
}
This pattern (UOW on application service methods + GET requests not starting transactions by default) is documented in ABP’s Unit of Work docs.
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.
@abp/ng.core (authentication helpers, RestService, localization, permission checks, etc.)@abp/ng.schematics (to generate API proxies)environment.ts with your ABP AuthServer/IdentityServer settings (issuer, clientId, redirectUri, scope, and apis.default.url).ClientId) in your AuthServer/IdentityServer seeding (and allow the Mini App origin in CORS / redirect URLs).abp generate-proxy -t ng -m identity -u https://<your-authserver-or-gateway-url>
AuthService to redirect to login, and use the generated proxies (or RestService) for API integration.@abp/ng.core.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.
No—a timeout is not caused by ConcurrencyStamp itself. ConcurrencyStamp is just an optimistic concurrency token (a string) that EF Core includes in the WHERE clause to ensure “update only if nobody else changed it”. If the stamp doesn’t match, you get an AbpDbConcurrencyException / DbUpdateConcurrencyException (0 rows affected), not a 30s timeout.
A 30-second timeout on this statement almost always means SQL Server is waiting on locks (blocking) or being throttled. Even a single-row update can sit and wait if:
What to do (actionable, ABP-relevant):
Confirm it’s blocking (most likely)
When the timeout happens, you should see the session in a WAIT state (e.g., LCK_M_...) on Azure SQL. If it’s blocking, the fix is to find and eliminate the long transaction / hot row contention (not to change concurrency stamp behavior).
Increase the EF Core command timeout (mitigation) Configure ABP’s DbContext options to raise command timeout so transient blocking/throttling doesn’t fail at 30 seconds:
using Volo.Abp.EntityFrameworkCore;
Configure<AbpDbContextOptions>(options =>
{
options.Configure(cfg =>
{
cfg.DbContextOptionsBuilder.CommandTimeout(180);
});
});
Id) you can get lock queues and timeouts. In such cases, you typically need to redesign to reduce hot-row updates (e.g., avoid repeatedly updating audit/concurrency fields for “heartbeat”-like writes), or use a distributed locking / coordination approach around that critical section.(Concurrency token docs, 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.
The SQL you posted is an optimistic concurrency update generated by EF Core (ABP uses ConcurrencyStamp on aggregate roots like IdentityUser, etc.). A timeout on a single-row UPDATE ... WHERE Id AND ConcurrencyStamp with ~900 rows is almost never caused by table size; it’s typically caused by blocking/locking (another transaction holds a lock on that row/table) or resource pressure (DTU/vCore throttling) on Azure SQL after the upgrade.
With ABP 10 you are very likely also on a newer .NET/EF Core version than ABP 8 (EF Core 8 vs EF Core 6/7 depending on your starting point). That doesn’t “break” this statement, but it can change overall behavior (more queries, different batching, different execution plans), which can expose existing locking issues under load.
Do these ABP-specific fixes/mitigations (safe and commonly used):
*.EntityFrameworkCore module where you call Configure<AbpDbContextOptions>:using Volo.Abp.EntityFrameworkCore;
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
options.Configure(cfg =>
{
// Increase as needed (seconds)
cfg.DbContextOptionsBuilder.CommandTimeout(180);
});
});
}
This doesn’t solve blocking, but prevents “false failures” during short spikes/throttling.
Identify and remove blocking transactions (most common root cause) In Azure SQL, check for blocking at the time of the issue (Query Store / “Blocked process” views / running requests). The symptom you see (timeout on a simple update with concurrency check) is consistent with:
ABP microservices commonly use distributed events/outbox patterns; if you have a consumer that updates the same entity repeatedly inside a long unit-of-work, it can block other writers.
Ensure your Azure SQL tier/performance didn’t effectively downgrade After upgrade, overall DB activity usually increases (more features/modules, more permission/setting/cache reads/writes). On low tiers, Azure SQL may throttle and cause timeouts even on trivial statements.
Make sure SQL Server compatibility is supported ABP 8 migration notes remind that starting with EF Core 8.0, generated SQL requires newer SQL Server versions (SQL Server 14+). Azure SQL with compat level 2019 is fine, but this confirms the “version support” angle is not your problem here—again pointing back to blocking/throttling.
If you apply (1) and still see timeouts, treat it as a blocking/throttling problem rather than an ABP/EF bug: the specific statement is a single-row concurrency update, so it should complete instantly unless it’s waiting.
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.
PermissionManagementOptions.SaveStaticPermissionsToDatabase is true, which is the default).admin role is not done by every microservice. By design, only the Administration microservice seeds/grants permissions to the admin role. So it’s expected to see permissions defined/registered, but no rows in AbpPermissionGrants for admin until Administration performs the seeding.What to do (definitive steps):
Start/restart the Administration microservice
admin role automatically (or you can grant them manually in the UI).If you are using Redis/distributed cache, clear it
(Optional, if you want it always automatic per service) Create a data seeder that uses IPermissionDataSeeder
IPermissionDataSeeder to grant permissions to the admin role (the same approach referenced in the microservice permission management doc).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.
They are inside the Basic Theme package’s embedded resources. In the ABP Framework source code, you can see (and copy from) them here:
Basic Theme root project (contains all the .cshtml files):
modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
Layouts (.cshtml):
modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts
(e.g., Themes/Basic/Layouts/Application.cshtml, Themes/Basic/Layouts/Account.cshtml)
Theme view components (.cshtml):
modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/...
(e.g., navbar, toolbar, brand, etc.)
To override any of these in your app, create the same relative path in your Web project (e.g., Themes/Basic/Layouts/Application.cshtml) and your file will override the theme’s embedded one.
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.