Fix (works for both “Modules page is blank” and “can’t download pro module source code” cases):
abp logout
abp login
abp suite
If you’re on the Business plan and still can’t download Elsa module source
Please contact us here (so the team can verify your license/module access and fix the download entitlement):
https://abp.io/contact
(Validated links: https://abp.io/contact , https://abp.io/docs/latest/studio/overview)
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.
Create a regular MVC controller action that decides (at runtime) which ViewComponent to render, then returns the ViewComponent result.
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
public class DynamicComponentController : AbpController
{
[HttpGet]
public IActionResult Render(string component, string id)
{
// Decide at runtime (example mapping/whitelist)
// IMPORTANT: whitelist allowed components, do NOT allow arbitrary type names from the client.
var allowed = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["OrderSummary"] = "OrderSummary", // VC name
["CustomerCard"] = "CustomerCard"
};
if (!allowed.TryGetValue(component, out var viewComponentName))
{
return BadRequest("Unknown component.");
}
// Pass parameters to the VC (anonymous object becomes arguments)
return ViewComponent(viewComponentName, new { id });
}
}
This lets you call /DynamicComponent/Render?component=OrderSummary&id=123 from AJAX and receive ready-to-insert HTML.
ABP’s AbpViewComponent is the typical base class.
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
public class OrderSummaryViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke(string id)
{
// load model, build view model, etc.
return View("~/Components/OrderSummary/Default.cshtml", model: id);
}
}
Example with fetch:
<div id="dynamic-area"></div>
<script>
async function loadComponent(component, id) {
const url = `/DynamicComponent/Render?component=${encodeURIComponent(component)}&id=${encodeURIComponent(id)}`;
const resp = await fetch(url, { headers: { "X-Requested-With": "XMLHttpRequest" }});
const html = await resp.text();
document.getElementById("dynamic-area").innerHTML = html;
}
</script>
Type.GetType(...) them. Always use a server-side whitelist/mapping (as shown).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.
What you did (Object Extension + EF Core mapping) only extends the entity and database schema. It does not automatically extend the Payment module’s MVC UI (datatable columns, create/edit forms, etc.).
The reason your IdentityUser extension shows up in the UI is that Identity module’s UI is integrated with the “module entity extension” UI system (ABP Commercial feature). The Payment module’s “Payment Requests” UI does not automatically render arbitrary extension properties as extra columns.
So you are not missing an EF mapping step. You need to extend/customize the MVC UI of the Payment module explicitly.
Overriding the entire page source:
Since this is a PRO/commercial module UI customization, and I can’t reliably fetch/verify the Payment module page source or the exact supported UI extension points right now (tooling access issue), the safest, verified next step is to contact ABP support so they can point you to the exact page/extension-point for “Payment Requests” in v10.0.3 MVC:
References (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.
Avoid “dynamic table name” access through EF Core repositories. In ABP (and EF Core), a repository is designed around a fixed entity mapping. Switching the underlying table name at runtime typically pushes you outside of EF Core’s normal model mapping and can easily bypass ABP’s cross-cutting features (unit of work boundaries, data filters like soft-delete/multi-tenancy, auditing, etc.) unless you re-implement them carefully.
Recommended approach (still repository-based): model the dynamic tables explicitly, then select the repository/service at runtime.
DbSet<TEntityX> + mapping for each target table (per template/table).If you truly have “same schema, multiple tables” (e.g., PresentationData_1, PresentationData_2, ...), EF Core has a concept that ABP can support in advanced scenarios via the repository’s EntityName (meant for EF Core shared-type entity types). You’d configure multiple named entity mappings in your DbContext and then choose which mapping to use by setting the repository’s entity name before executing operations.
public class MyAppService : ApplicationService
{
private readonly IRepository<PresentationRow, Guid> _repo;
public MyAppService(IRepository<PresentationRow, Guid> repo)
{
_repo = repo;
}
public async Task<List<PresentationRow>> GetRowsAsync(string templateKey)
{
_repo.SetEntityName(templateKey); // selects the named mapping configured in EF Core model
return await _repo.GetListAsync();
}
}
This keeps you in the repository/UoW world, but requires correct EF Core model configuration for each named mapping.
When direct table access is acceptable in ABP: If the data is not part of your domain model (purely “reporting / template rendering / denormalized read model”), consider implementing a dedicated Dapper-based or raw SQL query service in the Infrastructure layer and keep it read-only. Then you still benefit from ABP’s Unit of Work by ensuring the method runs inside a UoW (default in app services), while not trying to force dynamic tables into EF Core entity mapping.
What I would not advise: building SQL by concatenating table names from user input. If you must choose a table dynamically, only allow it from a strict whitelist (your dictionary) and keep the SQL parameterized for values.
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.
LastName column to AbpUsers (IdentityUser)
*.Domain.Shared project (YourProjectNameModuleExtensionConfigurator.cs), inside ConfigureExtraProperties:using System.ComponentModel.DataAnnotations;
using Volo.Abp.ObjectExtending;
ObjectExtensionManager.Instance.Modules().ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>(
"LastName",
options =>
{
options.Attributes.Add(new StringLengthAttribute(64));
}
);
});
});
*.EntityFrameworkCore project (YourProjectNameEfCoreEntityExtensionMappings.cs):using Volo.Abp.Identity;
using Volo.Abp.ObjectExtending;
ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityUser, string>(
"LastName",
(_, propertyBuilder) =>
{
propertyBuilder.HasMaxLength(64);
propertyBuilder.HasDefaultValue("");
}
);
Add-Migration Added_LastName_To_AbpUsersUpdate-DatabaseShow Surname as “Middle Name” only on the UI
Surname) if you want to keep ABP’s defaults; just change the label/display text in the registration UI.Surname).Make the registration page order: Name, Middle Name (Surname), Last Name
.cshtml.Name → first inputSurname → second input (but label it “Middle Name”)ExtraProperties["LastName"] (or your strongly typed extension) → third inputIf you want LastName to be saved during registration
ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToApi(...) in the host where the Account endpoints run (AuthServer/HttpApi.Host), including the relevant DTO types.Less obvious references:
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 add-package Volo.Abp.Imaging.ImageSharp
abp add-package Volo.Abp.Imaging.AspNetCore
using Volo.Abp.BlobStoring;
namespace MyCompany.MyProject;
[BlobContainerName("user-images")]
public class UserImageContainer
{
}
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.Imaging;
namespace MyCompany.MyProject.Controllers;
[Controller]
[Route("api/image")]
public class ImageController : ControllerBase
{
private readonly IBlobContainer<UserImageContainer> _blobContainer;
public ImageController(IBlobContainer<UserImageContainer> blobContainer)
{
_blobContainer = blobContainer;
}
[HttpPost("upload")]
[CompressImage]
[ResizeImage(width: 200, height: 200)]
public async Task<IActionResult> UploadAsync(IFormFile file)
{
var fileBytes = await file.GetAllBytesAsync(); // ABP extension method
await _blobContainer.SaveAsync(file.FileName, fileBytes, overrideExisting: true);
return Ok();
}
}
[HttpGet("{fileName}")]
public async Task<byte[]> GetAsync(string fileName)
{
return await _blobContainer.GetAllBytesAsync(fileName);
}
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.
www.website.com/@handle (path-based) the cleanest approach in ABP is to treat the handle as a route segment and then (optionally) adjust PathBase so that link generation works correctly across the UI—exactly the same pattern ABP uses for “tenant in the route”.handle@www.website.com (subdomain / host-based) this is not valid DNS/URL syntax (the @ is not a host label separator). If you meant handle.website.com, that’s host-based routing and should be implemented via subdomains (and optionally ABP’s domain-based tenant resolution). The rest of this answer focuses on the working pattern: /{handle} or /@{handle}./{handle} or /@{handle}/@handle and moves it into PathBaseThis preserves ABP’s routing and also makes relative URLs/navigation work (because the app “thinks” it’s hosted under /@handle).
Put this before app.UseRouting() in your Web/HttpApi.Host OnApplicationInitialization:
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
app.Use(async (httpContext, next) =>
{
// Matches: /@john or /@john/... (handle chars: letters, numbers, underscore, dot, dash)
var match = Regex.Match(httpContext.Request.Path, @"^/@([a-zA-Z0-9_.-]+)(?:/.*)?$");
if (match.Success)
{
var handle = match.Groups[1].Value;
// OPTIONAL: validate handle exists (recommended)
// var handleStore = httpContext.RequestServices.GetRequiredService<IUserHandleStore>();
// if (await handleStore.ExistsAsync(handle))
{
if (httpContext.Request.Path.StartsWithSegments(new PathString("/@" + handle),
out var matchedPath,
out var remainingPath))
{
var originalPath = httpContext.Request.Path;
var originalPathBase = httpContext.Request.PathBase;
httpContext.Request.Path = remainingPath;
httpContext.Request.PathBase = originalPathBase.Add(matchedPath);
try
{
await next();
}
finally
{
httpContext.Request.Path = originalPath;
httpContext.Request.PathBase = originalPathBase;
}
return;
}
}
}
await next();
});
app.UseRouting();
// ...
}
What this gives you:
/@john/posts/42 is internally rewritten to:
PathBase = "/@john"Path = "/posts/42"/posts/{id}), while the UI still works under the handle prefix.A simple approach is to read it from HttpContext.Request.PathBase:
public static class HandleHttpContextExtensions
{
public static string? GetHandleFromPathBase(this HttpContext httpContext)
{
var pb = httpContext.Request.PathBase.Value; // e.g. "/@john"
if (string.IsNullOrWhiteSpace(pb)) return null;
return pb.StartsWith("/@") ? pb.Substring(2) : null;
}
}
Then in a controller/page/app service (via IHttpContextAccessor) you can resolve the “current private site owner” and load data accordingly.
You do not need special ABP routing features for this. Keep your normal endpoints, e.g.:
[Route("posts")]
public class PostsController : AbpController
{
[HttpGet("{id}")]
public IActionResult Get(int id) => Ok();
}
PathBase technique is proven in ABP for multi-tenancy “tenant in route” scenarios (it avoids broken navigation links and incorrect base paths).PathBase middleware pattern used for route-based resolution in ABP)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.
IFormFile*.HttpApi.Host or *.HttpApi depending on your structure).[CompressImage][ResizeImage(width, height)]This lets you implement “upload → auto compress/resize → save” with minimal code.
ABP does not provide a first-party background removal / segmentation feature. However, ABP’s modularity + DI makes third-party integration straightforward:
IOptions, and call it from your upload/application service.HttpApi.Host (tiered backend).A typical flow:
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.
using Quartz;
using Volo.Abp.BackgroundWorkers.Quartz;
public class RetinaImageNightlyWorker : QuartzBackgroundWorkerBase
{
public RetinaImageNightlyWorker()
{
JobDetail = JobBuilder.Create<RetinaImageNightlyWorker>()
.WithIdentity(nameof(RetinaImageNightlyWorker))
.Build();
// Example: run every 30 minutes (then decide per-tenant “is it night?” inside Execute)
Trigger = TriggerBuilder.Create()
.WithIdentity(nameof(RetinaImageNightlyWorker))
.WithCronSchedule("0 0/30 * * * ?")
.Build();
ScheduleJob = async scheduler =>
{
if (!await scheduler.CheckExists(JobDetail.Key))
{
await scheduler.ScheduleJob(JobDetail, Trigger);
}
};
}
public override async Task Execute(IJobExecutionContext context)
{
// Resolve your app/domain service(s) and:
// 1) iterate tenants
// 2) if tenant local time is within night window => process a batch of images
}
}
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.
(There is no verified source available in the public docs/release notes that documents an “AI off” toggle for ABP Studio 3.0.1.)
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.