[maliming] said: hi
The
Actionswill be populated after the method is executed.You can create a new Action in your method. Then merge them in your
AuditLogContributorThanks.
What about the rest of the questions? How can more than one AuditLogActionInfo be recorded?
[maliming] said: hi
We want to add a descriptive name in the ExtraProperties of AuditLogActionInfo
Option B: Use a custom AuditLogContributor is the best choice.
Is this the correct way to add information from an AppService method?
Audit log contributors, was explained above, is a global way of manipulating the audit log object. It is good if you can get a value from a service.
Injecting
IAuditingManagerservice will be good.Thanks,
Hello, after running debugging tests, I have observed the following:

It is a method in my app service. When I inject IAuditingManager, I see that it does not have the current action. I only see the possibility of adding information as extra properties in the log.
My idea was to do it in the action of that app service method, since in the logging module documentation, an AuditLogInfo can have many AuditLogActionInfo. After reviewing my database, I see that only 1 AuditLogActionInfo is recorded for each AuditLogInfo.
Why is this relationship like this? How can more than one AuditLogActionInfo be recorded? Any suggestions for saving customised information in the event action?
https://abp.io/docs/latest/framework/infrastructure/audit-logging
We are implementing a custom audit system based on ABP Framework's Audit Logging module. We have successfully implemented an AuditLogsAppService that allows us to query audit logs from the AbpAuditLogs and AbpAuditLogActions tables.
Currently we can:
We have two additional requirements to enrich audit information:
Goal: Store custom descriptive names for actions instead of only using technical method names.
Current Situation: When an audit action is logged, we get technical information like:
ServiceName: "Entity1CrudAppService"MethodName: "CreateAsync"What We Need:
We want to add a descriptive name in the ExtraProperties of AuditLogActionInfo, for example:
ExtraProperties["ActionDisplayName"] = "Create Entity1"ExtraProperties["ActionCategory"] = "CRUD Operations"ExtraProperties["MyCustomValue"] = "MyCustomValue From Method XXX"Usage Example:
public class Entity1CrudAppService : ApplicationService
{
// When executing this method, we want it to be logged as:
// ServiceName: "Entity1CrudAppService"
// MethodName: "CreateAsync"
// ExtraProperties["ActionDisplayName"] = "Create Entity1"
public async Task<EntityDto> CreateAsync(CreateEntityDto input)
{
// ... method logic
}
}
Question 1:
What is the recommended way to add these custom properties to AuditLogActionInfo?
We have considered:
Option A: Use a custom attribute on methods
[AuditActionName("Create Entity1", Category = "CRUD")]
public async Task<EntityDto> CreateAsync(CreateEntityDto input)
Option B: Use a custom AuditLogContributor
public class CustomActionNameContributor : AuditLogContributor
{
public override void PostContribute(AuditLogContributionContext context)
{
// How do we access current method information to add properties?
}
}
Option C: Another approach you recommend
Goal: From within an AppService method, be able to add custom information to the current audit log.
Scenario: In a specific method, we want to record additional business information that is relevant for auditing.
Use Case Example:
public class ProjectsAppService : ApplicationService
{
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
// Create the project
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
// HERE: We want to add additional information to the current audit log
// For example:
// - Created project budget
// - Project category
// - Approver user if exists
// ❓ How do we add this information to the current AuditLog?
return ObjectMapper.Map<Project, ProjectDto>(project);
}
public async Task ApproveProjectAsync(Guid projectId)
{
var project = await _repository.GetAsync(projectId);
project.Approve(CurrentUser.Id);
// HERE: We want to record specific approval information
// - Previous project state
// - Approved amount
// - Approval comments
// ❓ How do we add this information to the current AuditLog?
await _repository.UpdateAsync(project);
}
}
What We Know:
According to ABP documentation, we can access the current audit scope:
public class MyService : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MyService(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task DoItAsync()
{
var currentAuditLogScope = _auditingManager.Current;
if (currentAuditLogScope != null)
{
currentAuditLogScope.Log.Comments.Add("Custom comment");
currentAuditLogScope.Log.SetProperty("MyCustomProperty", 42);
}
}
}
Question 2:
AuditLogActionInfo of the current method, or only to the general AuditLogInfo?When querying logs, we want to see:
{
"auditLogId": "guid",
"executionTime": "2026-01-21T10:30:00",
"actions": [
{
"serviceName": "ProjectsAppService",
"methodName": "CreateAsync",
"executionDuration": 250,
"extraProperties": {
"ActionDisplayName": "Create Project",
"ActionCategory": "Project Management",
"EntityType": "Project"
}
}
]
}
{
"auditLogId": "guid",
"executionTime": "2026-01-21T10:30:00",
"actions": [
{
"serviceName": "ProjectsAppService",
"methodName": "CreateAsync",
"executionDuration": 250,
"extraProperties": {
"ProjectBudget": 50000,
"ProjectCategory": "Infrastructure",
"ApprovalRequired": true
}
}
],
"extraProperties": {
"BusinessOperation": "ProjectCreation",
"Department": "Engineering"
}
}
What is the recommended way in ABP to add custom properties to AuditLogActionInfo?
Is there any attribute or interceptor mechanism to add metadata to audit actions?
How can we access the current action (AuditLogActionInfo) from within an AppService method to add specific properties?
Are there examples or documentation about similar use cases?
Is it possible to extend the audit system without modifying ABP source code?
public class ProjectsAppService : ApplicationService, IProjectsAppService
{
private readonly IRepository<Project> _repository;
public ProjectsAppService(IRepository<Project> repository)
{
_repository = repository;
}
[AuditActionName("Create Project", Category = "Project Management")]
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
return ObjectMapper.Map<Project, ProjectDto>(project);
}
[AuditActionName("Update Project", Category = "Project Management")]
public async Task<ProjectDto> UpdateAsync(Guid id, UpdateProjectDto input)
{
var project = await _repository.GetAsync(id);
project.Update(input.Name, input.Budget);
await _repository.UpdateAsync(project);
return ObjectMapper.Map<Project, ProjectDto>(project);
}
}
public class ProjectsAppService : ApplicationService, IProjectsAppService
{
private readonly IRepository<Project> _repository;
private readonly IAuditingManager _auditingManager;
public ProjectsAppService(
IRepository<Project> repository,
IAuditingManager auditingManager)
{
_repository = repository;
_auditingManager = auditingManager;
}
public async Task<ProjectDto> CreateAsync(CreateProjectDto input)
{
var project = new Project(input.Name, input.Budget);
await _repository.InsertAsync(project);
// Add business information to audit log
var auditScope = _auditingManager.Current;
if (auditScope != null)
{
// ❓ How do we add properties to the CURRENT ACTION, not just the general log?
// This works but adds to general AuditLogInfo:
auditScope.Log.SetProperty("ProjectBudget", input.Budget);
// ❓ How do we do this for AuditLogActionInfo?
// auditScope.CurrentAction?.SetProperty("ProjectBudget", input.Budget);
}
return ObjectMapper.Map<Project, ProjectDto>(project);
}
}
auditScope.Log.Comments.Add($"Project created with budget: {input.Budget}");
Problem: Comments are plain text, not structured. We prefer typed properties.
Problem: Parameters already contain method input information. We don't want to mix with calculated or business information.
Problem: Would duplicate functionality and wouldn't leverage ABP's system.
A solution that allows us to:
AuditLogsAppServiceWe appreciate any guidance, code examples, or documentation references that help us achieve these goals.
[maliming] said: hi
I'm not familiar with Azure.
Let’s make it clear:
- Can you use a different subdomain in Azure for tenants?
eg: https://tenant1.myazure.com https://tenant2.myazure.com
- For each tenant, I need to configure several URLs for login and logout. Even if it is only one per customer, there are more than one of those customers.
Where do you need to confiture URL? In the database or Azure?
Because you can use a wildcard redirect URL and a post-redirect URL in the database.
Thanks.
[maliming] said: hi
If you use a path as a tenant name, you don't need to use sub-domains. Path or subdomain you can only select one. I recommend to use sub-domain.
100 or 256 tenants are not enough for you?
Thanks.
For each tenant, I need to configure several URLs for login and logout. Even if it is only one per customer, there are more than one of those customers.
I know that this should be resolved with subdomains or paths, but not with both. That is not the question. The question is how to resolve it using Azure as an external provider.
[maliming] said: hi
Do you mean Azure doesn't support https://abp.io/community/articles/resolving-tenant-from-route-in-abp-framework-ah7oru97
Thanks.
No, sorry, what I mean is that with this way of resolving the tenant, using the path, should I also configure the URLs with the wildcard in Azure App Registration, the original problem in this thread (with subdomains).
In Azure App Registrations, I have to configure the return URLs. I cannot add one URL per client due to a limitation in Azure itself, nor does it allow me to add wildcards, which is the recommended practice.
https://learn.microsoft.com/en-us/entra/identity-platform/reply-url#maximum-number-of-redirect-uris-and-uri-length https://learn.microsoft.com/en-us/entra/identity-platform/reply-url#restrictions-on-wildcards-in-redirect-uris
[maliming] said: hi
You can see : https://abp.io/community/articles/resolving-tenant-from-route-in-abp-framework-ah7oru97
But using sub-domains will be easy.
Thanks.
Even so, the URL limitation in Azure remains; I cannot use wildcards. Does it support this?
[maliming] said: hi
Wildcard Support: Azure AD B2C does support wildcards in redirect URIs (e.g., https://*.app-app1-qa.commondomain.com/authentication/login), but Microsoft does not recommend this practice for security reasons.
I think you have to use wildcard domains for your apps.
Correlation cookie
You can configure this cookie share across wildcard domains.
See https://abp.io/community/articles/how-to-share-the-cookies-between-subdomains-jfrzggc2#gsc.tab=0
Thanks.
After several attempts, it has not worked.
Would it be possible to resolve the tenant in another way, similar to how Azure DevOps does it?
Something like: http:app.commondomain.com/tenant1/entity
Hello ABP Team,
Following the successful resolution of ticket #10222 regarding Domain/Subdomain Tenant Resolver implementation, we have encountered a critical issue when integrating this functionality with Azure AD B2C as an external authentication provider.
The domain/subdomain tenant resolution works perfectly in local development environments using OpenIddict, but fails when Azure AD B2C is enabled as the external provider, which is required for our QA, Preproduction, and Production environments in Azure.
Our application is deployed with environment-based subdomains and tenant resolution:
QA: https://tenant1.app-app1-qa.commondomain.com
Preproduction: https://tenant2.app-app1-pre.commondomain.com
Production: https://tenant3.app-app1.commondomain.com
The tenant (e.g., tenant1, tenant2) is resolved from the first subdomain label, following the implementation described in ticket #10222.
Following the solution provided by @maliming in ticket #10222, we successfully implemented:
AbpOpenIddictWildcardDomainOptions configuration with wildcard domain formatsAbpTenantResolveOptions with domain-based tenant resolversTokenWildcardIssuerValidator for JWT validation with wildcard issuersMyWebAssemblyMultiTenantUrlProvider in Blazor WASM client to extract tenant from subdomainResult: ✅ Works perfectly in local development with OpenIddict.
When attempting to replicate this behavior in Azure environments using Azure AD B2C as the external provider, we encounter authentication flow failures.
We identified a fundamental conflict between Azure AD B2C requirements and the subdomain-based tenant resolution strategy:
Current Redirect URIs registered in Azure AD B2C "App1 QA" app:
https://app-app1server-qa-qa-we-001.azurewebsites.net/signin-azuread-oidchttps://server-app1-qa.commondomain.com/signin-azuread-oidchttps://localhost:44329/signin-azuread-oidchttps://app-app1-qa.commondomain.com/authentication/loginhttps://app-app1-qa.commondomain.com/authentication/logouthttps://app-app1-qa.commondomain.com/signout/B2C_1_signupsignin01https://app-app1-qa.commondomain.com/signin-azuread-oidchttps://localhost:44385/signin-azuread-oidchttps://localhost:44385/authentication/logouthttps://localhost:44385/authentication/loginhttps://localhost:44385/signout/B2C_1_signupsignin01The Problem: To support subdomain-based tenant resolution, we would need to register one redirect URI per tenant, for example:
https://tenant1.app-app1-qa.commondomain.com/authentication/loginhttps://tenant2.app-app1-qa.commondomain.com/authentication/loginhttps://tenant3.app-app1-qa.commondomain.com/authentication/loginAzure AD B2C Limitation: According to Microsoft documentation, there is a hard limit on the number of redirect URIs that can be registered per App Registration.
This makes the manual registration approach not scalable for multi-tenant scenarios with subdomain resolution.
Wildcard Support: Azure AD B2C does support wildcards in redirect URIs (e.g., https://*.app-app1-qa.commondomain.com/authentication/login), but Microsoft does not recommend this practice for security reasons.
After researching and implementing various solutions found in documentation and forums, we have advanced in the authentication flow but now encounter a correlation cookie error:
'.AspNetCore.Correlation.Kh3ihYshY6FPVHu7SpFA9Uka76CC_IBMV0yO8yMcZxQ' cookie not found.
This error indicates that the correlation cookie used by ASP.NET Core during the OAuth/OpenID Connect authentication flow is not found or is not available when Azure AD B2C attempts to redirect back to the application.
Potential causes:
https://tenant1.app-app1-qa.commondomain.comtenant1 is automatically resolved from the subdomaintenant1) remains correctly applied throughout the sessionhttps://tenant1.app-app1-qa.commondomain.comtenant1 is correctly resolved from the subdomainThe primary use case for this functionality is to facilitate direct links to specific entities without requiring manual tenant specification.
Previous URL (without automatic resolution):
https://app-app1-qa.commondomain.com/Entity/36512651
Users had to manually select their tenant before accessing the patient record.
With subdomain-based tenant resolution, the tenant is automatically resolved from the URL:
Improved URL (with automatic resolution):
https://tenantCliente.app-app1-qa.commondomain.com/Entity/36512651
The system automatically detects tenantCliente from the subdomain, configures the appropriate context, and allows direct access to the record without intermediate steps.
This works perfectly in local development with OpenIddict, but fails when Azure AD B2C is enabled.
Is the Domain/Subdomain Tenant Resolver compatible with Azure AD B2C external authentication providers?
Are there additional configurations or workarounds required to make subdomain-based tenant resolution work with Azure AD B2C?
How can we resolve the correlation cookie error when using subdomains with Azure AD B2C authentication?
Is there a recommended approach for handling redirect URI configuration in Azure AD B2C for multi-tenant applications with subdomain resolution?
Are there known limitations or incompatibilities between:
Has ABP team tested or validated the Domain/Subdomain Tenant Resolver with Azure AD B2C in production scenarios?
We have tried various approaches to integrate Azure AD B2C, including:
None of these attempts have successfully resolved the correlation cookie error when using subdomain-based tenant resolution with Azure AD B2C.
We would greatly appreciate:
Official guidance or documentation on integrating Domain/Subdomain Tenant Resolver with external authentication providers like Azure AD B2C
Sample implementation or reference project demonstrating this integration
Clarification on whether this scenario is supported in the current ABP Framework version
Recommended architectural patterns for handling this use case in production Azure environments
Any known workarounds or alternative approaches that maintain the automatic tenant resolution functionality while working with Azure AD B2C
Thank you in advance for any guidance or assistance you can provide.
Related Issues:
[maliming] said: hi
Can you share the debug logs of 44393 website?
Thanks
If you wish, I can give you access to the source code where I am implementing it, so you can run the application yourself and see what happens. Please contact me by email, francisco.sierra@semicrol.com