In the latest ABP Studio, Angular UI now defaults to the standalone component structure, but module-based (NgModule) DDD modules are still supported for backwards compatibility. When adding a new DDD module, you can select the user interface type (including Angular) as before.
The process is:
Add > New Module > DDD Module
.If you want to use the previous module-based structure instead of the new standalone approach, ABP Studio and ABP Schematics still support both. When generating a library or module, you will be prompted to select the template type: "module" (classic NgModule) or "standalone" (new Angular structure). Choose "module" to keep the old behavior.
Both approaches are maintained for compatibility, so you can continue to add Angular DDD modules as before by selecting the appropriate template type during module creation.
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.
When creating a new solution in ABP Studio, the solution name you provide in the wizard should be used as the actual solution name. The behavior where ABP Studio replaces your chosen name with "AbpSolution1", "AbpSolution2", etc., is not expected and does not align with the documented workflow.
This issue may be related to a bug in the ABP Studio version distributed via the Microsoft Store. The official documentation and release notes do not mention this as standard or intended behavior. The ABP CLI, as you observed, correctly uses the provided solution name.
Recommended Actions:
Help -> Check for Updates
or download the latest version directly from the official site: https://abp.io/studioFor now, using the ABP CLI is a valid workaround, as it respects your provided solution name.
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.
Thank you for the detailed analysis and proposed solutions regarding the IdentityLinkUser query performance issue in ABP Framework 9.2.1. Your assessment is accurate and aligns with previously reported issues, including:
Your workaround using includeIndirect: false and batch fetching is a valid mitigation, but as you noted, it does not address the underlying inefficiency in the repository implementation.
Based on validated sources and the current state of the ABP Framework:
This issue has been reported and discussed in detail in the following support threads:
The root cause is the recursive, exclusion-based query pattern in the repository, which is not scalable for large numbers of linked users.
As of ABP 9.2.1 (and up to 9.2.3), there is no built-in support for recursive CTEs or temp table-based solutions in the IdentityLinkUserRepository. The current implementation still relies on iterative exclusion, leading to parameter explosion.
Your proposed solution using a recursive CTE is the recommended approach for SQL Server and would resolve the parameter limit and performance issues. However, this is not yet implemented in the official ABP modules.
The ABP team has acknowledged the problem in the referenced support threads, and partial improvements (such as GetListByIdsAsync) have been made, but a full repository-level fix (e.g., CTE-based querying) is not yet available.
Recommended Actions:
Summary:
The parameter explosion in IdentityLinkUserRepository.GetListAsync() is a known and validated issue. The most effective solution is to implement a recursive CTE or similar efficient query strategy. Until this is available in the official ABP release, your workaround is the best practice.
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.
The duplicated and cancelled /api/abp/application-configuration
requests you observe are typically caused by the browser or frontend framework (Angular) making multiple requests in quick succession, often due to application initialization logic or HTTP interceptors. In ABP Angular applications, this endpoint is called on startup to load configuration and localization data.
The cancellation and duplication can also occur if a previous request is superseded by a new one before the first completes, or if the user navigates quickly, causing Angular to re-initialize services. The log shows a System.OperationCanceledException
, which is expected when a request is aborted.
This behavior is not unique to ABP; it is common in SPAs (Single Page Applications) and is generally harmless unless it causes user-facing issues or performance problems. If you want to further analyze or reduce such requests, consider:
For more details on monitoring HTTP requests in ABP Studio and troubleshooting, see the official documentation:
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.
To address the issue of external font imports in LeptonX's font-bundle.css causing timeouts in restricted environments, you have a few options:
/* font-bundle.css overridden to remove external font imports */
Remove or Replace the @import in the Build Pipeline:
Use Local Fonts:
No Built-in Configuration (as of v9.2.3):
This approach aligns with common ABP and LeptonX theme customization practices for restricted environments.
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.
To ensure OpenIddict uses the latest (unexpired) certificates and avoids downtime when certificates expire, you need to register both the new and old certificates in the credentials collection during key rollover. OpenIddict will only use valid (unexpired) certificates for signing and encryption, and will refuse expired ones. If only expired certificates are present, authentication will fail and your site will go offline.
Solution Steps:
PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
{
serverBuilder.AddSigningCertificate(new X509Certificate2("old-cert.pfx", "oldPassword"));
serverBuilder.AddSigningCertificate(new X509Certificate2("new-cert.pfx", "newPassword"));
});
Automate Certificate Renewal and Reload:
Self-Signed/Expired Certificates:
Troubleshooting:
When using X.509 encryption credentials, at least one of the registered certificates must be valid
, it means all provided certificates are expired or invalid..pfx
file is present, the password is correct, and the certificate is not expired.References:
This approach ensures seamless certificate rollover and prevents downtime due to expired certificates.
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 error occurs because ABP Suite is generating a using importContryProj.ManagementService.Shared; statement, but there is no Shared project or namespace in your microservice solution. In ABP microservice templates, the "Shared" project is not created by default for each service; it is only present in some monolithic or modular setups.
When you add a navigation property (relation) between entities in a microservice service (like ManagementService), ABP Suite expects a Shared project to exist for DTO sharing, but your solution structure does not include it. This results in the CS0234 error: The type or namespace name 'Shared' does not exist in the namespace.
To resolve this:
This is a known limitation when using ABP Suite with microservice templates, as the code generator assumes a Shared project exists for each service. You may need to adjust the generated code manually or create the missing Shared project.
Sources:
This approach aligns with common ABP microservice conventions, but specific official documentation for this exact scenario is not available.
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.
To add Azure AD as an external provider with dynamic options in ABP, you need to ensure that the dynamic options are properly initialized before the authentication middleware tries to use them. The error you are seeing (ArgumentNullException: Value cannot be null. (Parameter 'ClientId')
) occurs because the ClientId
(and possibly other required properties) are not set at application startup, so the OpenIdConnect middleware fails validation.
Here's the correct approach for dynamic external login providers in ABP:
Register Dynamic Options and Post-Configure Handler
You must use .WithDynamicOptions<OpenIdConnectOptions, OpenIdConnectHandler>()
after adding the OpenIdConnect provider, and register a post-configure handler to ensure dynamic properties are set before validation.
context.Services.AddAuthentication()
.AddOpenIdConnect("AzureOpenId", "Azure AD", options =>
{
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("email");
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
options.CallbackPath = configuration["AzureAd:CallbackPath"]; // Optional if dynamic
})
.WithDynamicOptions<OpenIdConnectOptions, OpenIdConnectHandler>(
"AzureOpenId",
options =>
{
options.WithProperty(x => x.Authority);
options.WithProperty(x => x.ClientId);
options.WithProperty(x => x.ClientSecret, isSecret: true);
}
);
context.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<
IPostConfigureAccountExternalProviderOptions<OpenIdConnectOptions>,
OpenIdConnectPostConfigureAccountExternalProviderOptions>());
Implement the Post-Configure Handler
This ensures that after dynamic properties are set, the options are re-validated:
public class OpenIdConnectPostConfigureAccountExternalProviderOptions : IPostConfigureAccountExternalProviderOptions<OpenIdConnectOptions>
{
private readonly IEnumerable<IPostConfigureOptions<OpenIdConnectOptions>> _postConfigureOptions;
public OpenIdConnectPostConfigureAccountExternalProviderOptions(IEnumerable<IPostConfigureOptions<OpenIdConnectOptions>> postConfigureOptions)
{
_postConfigureOptions = postConfigureOptions;
}
public Task PostConfigureAsync(string name, OpenIdConnectOptions options)
{
foreach (var configureOption in _postConfigureOptions)
{
configureOption.PostConfigure(name, options);
}
return Task.CompletedTask;
}
}
Do Not Set Required Properties to Null at Startup
Do not leave ClientId
, Authority
, etc., unset at startup. The dynamic provider system will inject them at runtime, but the post-configure handler is required to ensure this happens after all dynamic properties are available.
Summary
.WithDynamicOptions
after .AddOpenIdConnect
.IPostConfigureAccountExternalProviderOptions
implementation.This approach ensures that the OpenIdConnect middleware does not throw validation errors at startup and that your dynamic configuration is applied correctly.
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.
In a distributed ABP Auth Server setup (such as Azure Aspire with multiple instances), you must ensure that both Data Protection keys and OpenIddict cryptographic keys are shared and synchronized across all instances. If not, you will see errors like "invalid_grant", "invalid_token", or "The signing key associated to the specified token was not found."
Using Azure Cache for Redis is a valid approach, but you must ensure:
To make your ABP Auth Server reliable in this environment:
context.Services.AddDataProtection()
.PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");
See: [Distributed Data Protection](https://abp.io/docs/abp/latest/Distributed-Data-Protection)
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
// For production, use a persisted certificate or key storage
See: [Distributed OpenIddict](https://abp.io/docs/abp/latest/Distributed-OpenIddict)
Ensure Redis is healthy and accessible from all instances. Any network or configuration issue can cause key desync.
If you want to remove Redis, you must use another distributed key store (e.g., Azure Blob Storage for Data Protection, or a shared certificate for OpenIddict). Do not use in-memory or local file storage in a multi-instance environment.
Restart all instances after changing key storage configuration to ensure all use the same keys.
If you see "The signing key associated to the specified token was not found," it means the instance that issued the token is not sharing its keys with others. This is almost always a misconfiguration of Data Protection or OpenIddict key storage.
For more details and code samples, see:
Summary:
You must use a distributed key store (like Redis or Azure Blob Storage) for both Data Protection and OpenIddict keys, and ensure all instances are configured identically. Do not use local or ephemeral keys in a multi-instance environment.
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.
To address your issue with user-level permissions not being applied in an ABP solution using the OpenIddict module (instead of IdentityServer), here are the key points and steps you should follow:
User vs. Role Permissions in ABP
OpenIddict vs. IdentityServer
PreConfigureServices
code for AbpIdentityServerBuilderOptions
.Troubleshooting User Permissions Not Applying
AbpPermissionGrants
table with the correct ProviderName
(U
for user, R
for role) and ProviderKey
(user ID).AuthorizeView
component in Blazor checks the current user's claims. If the permission is not present, it may be due to the claims not being refreshed or propagated to the client.Force Claims Refresh for User Permissions
app.UseDynamicClaims()
middleware is configured only in the AuthServer and Web projects, not in all microservices.AbpClaimsPrincipalFactoryOptions.IsDynamicClaimsEnabled
is set appropriately (usually true
for dynamic claims).Recommended Steps
Sample: Dynamic Claims Configuration
// In your AuthServer and Web module
context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
});
// In Startup/Program.cs
app.UseDynamicClaims();
IAuthorizationService.IsGrantedAsync
) to debug on the server side.Sources:
This approach aligns with common ABP conventions for OpenIddict and dynamic claims. If you follow these steps and the issue persists, please check for customizations or middleware that might interfere with claims propagation.
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.