- Steps to reproduce the issue:
- Follow https://abp.io/community/articles/how-to-change-the-currentuser-in-abp-i3uu1m7g#gsc.tab=0 using Hangfire background task
- Example code that is not working in our situation...
example deleted
- The example above is fired after someone changes a configuration. Generating files takes a while, So we needed a background job. We want the change to be logged in the audit log. But nothing gets logged, within the background job. The configuration change made by the user (outside the background job), is visible in the audit log.
- We use HangFire as background task scheduler.
private void ConfigureAuditing() { Configure<AbpAuditingOptions>(options => { options.IsEnabledForAnonymousUsers = false;
options.EntityHistorySelectors.Add(
new NamedTypeSelector(
"MySelectorName",
type =>
{
return type == typeof(Project) || type == typeof(Configuration);
}
)
);
});
}
9 Answer(s)
-
0
In ABP, audit properties like LastModifierId are set based on the current user, which is determined by the ClaimsPrincipal available via ICurrentPrincipalAccessor. In background jobs (such as Hangfire), there is no authenticated user by default, so audit logging will not automatically associate changes with a user unless you explicitly set the principal.
Your approach of using currentPrincipalAccessor.Change(newPrincipal) is correct and aligns with official ABP guidance. However, for audit logging to work, you must ensure:
- The ClaimsPrincipal you create contains at least the AbpClaimTypes.UserId claim.
- The code that modifies the entity and calls UpdateAsync runs inside the using block of currentPrincipalAccessor.Change.
- Auditing is enabled for the entity type (which you have configured).
If you still do not see audit logs for changes made in the background job, check the following:
- Ensure that the AbpAuditingOptions.IsEnabledForAnonymousUsers is set to true if the principal is not fully authenticated, or that your ClaimsPrincipal is constructed with the correct authentication type.
- Make sure the background job is not running in a separate scope where auditing is disabled or overridden.
- Confirm that the database context used for the update is the same as the one configured for auditing.
Example pattern (from official docs and community articles):
var newPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(AbpClaimTypes.UserId, user.Id.ToString()), new Claim(AbpClaimTypes.UserName, user.UserName) }, "CustomAuthType")); // Set an authentication type
using (currentPrincipalAccessor.Change(newPrincipal)) { // All repository updates here will use the specified user for audit logging await configurationRepository.UpdateAsync(configuration); }
- If you want to ensure auditing for anonymous/background users, set: ```csharp Configure<AbpAuditingOptions>(options => { options.IsEnabledForAnonymousUsers = true; });
For more details and verified patterns, see:
If you follow these steps and still do not see audit logs, double-check that your background job is not suppressing auditing or using a different DbContext or unit of work configuration.
Sources:
- https://abp.io/community/articles/how-to-change-the-currentuser-in-abp-i3uu1m7g#gsc.tab=0
- https://abp.io/docs/latest/framework/infrastructure/current-user
- https://abp.io/support/questions/6298
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.
-
0
This is not the answer.
-
0
hi
You can create an audit log scope in your job.
Please note that it does not support remote services and can only work within a single application.
https://abp.io/docs/latest/framework/infrastructure/audit-logging#manually-create-an-audit-log-scope
Thanks
-
0
Thanks for the response,
Now a log rule is fired, but with no properties. Even if i reload the configuration, within the scope, first.
using (currentPrincipalAccessor.Change(newPrincipal)) { using (var auditingScope = auditingManager.BeginScope()) { configuration = await configurationRepository.GetAsync(Convert.ToInt64(args.ProjectInfo?.ConfigurationId)); var advicefileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(pdfAdviceResponseTask.Result), adviceFileName)); var billOfMaterialsFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(pdfBillOfMaterialsResponseTask.Result), BillOfMaterialsFileName)); var anchoringZonesFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(Encoding.UTF8.GetBytes(anchoringZonesSVGTask.Result)), L["DownloadAnchoringDrawing:Filename", args.Configurator.RoofLayoutInformation.TypeOfRoof.Value.ToString()])); var zonesFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(Encoding.UTF8.GetBytes(zonesSVGTask.Result)), L["DownloadZoneDrawing:Filename", args.Configurator.RoofLayoutInformation.TypeOfRoof.Value.ToString()])); Task.WaitAll(advicefileTask, billOfMaterialsFileTask, anchoringZonesFileTask, zonesFileTask); args.Context?.WriteLine($"Started configuring files to database...'"); configuration.AdvicePDFId = advicefileTask.Result.Id; configuration.BillOfMaterialsPDFId = billOfMaterialsFileTask.Result.Id; configuration.AnchoringDrawingId = anchoringZonesFileTask.Result.Id; configuration.ZoneDrawingId = zonesFileTask.Result.Id; await configurationRepository.UpdateAsync(configuration); await auditingScope.SaveAsync(); } }
-
0
hi
Try to begin a new uow.
using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) { using (var auditingScope = auditingManager.BeginScope()) //// await uow.CompleteAsync(); }
https://abp.io/docs/latest/framework/architecture/domain-driven-design/unit-of-work#begin-a-new-unit-of-work
Thanks.
-
0
Thanks for the answer.
Nope, this does not help. Actually: how only the create (before the background job fires), the update is not visible in the audit log.
using (currentPrincipalAccessor.Change(newPrincipal)) { using (var uow = unitOfWorkManager.Begin(requiresNew: true)) { using (var auditingScope = auditingManager.BeginScope()) { configuration = await configurationRepository.GetAsync(Convert.ToInt64(args.ProjectInfo?.ConfigurationId)); var advicefileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(pdfAdviceResponseTask.Result), adviceFileName)); var billOfMaterialsFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(pdfBillOfMaterialsResponseTask.Result), BillOfMaterialsFileName)); var anchoringZonesFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(Encoding.UTF8.GetBytes(anchoringZonesSVGTask.Result)), L["DownloadAnchoringDrawing:Filename", args.Configurator.RoofLayoutInformation.TypeOfRoof.Value.ToString()])); var zonesFileTask = UploadFileAsync(new RemoteStreamContent(new MemoryStream(Encoding.UTF8.GetBytes(zonesSVGTask.Result)), L["DownloadZoneDrawing:Filename", args.Configurator.RoofLayoutInformation.TypeOfRoof.Value.ToString()])); Task.WaitAll(advicefileTask, billOfMaterialsFileTask, anchoringZonesFileTask, zonesFileTask); args.Context?.WriteLine($"Started configuring files to database...'"); configuration.AdvicePDFId = advicefileTask.Result.Id; configuration.BillOfMaterialsPDFId = billOfMaterialsFileTask.Result.Id; // TODO: aanpassen naar billofmaterials configuration.AnchoringDrawingId = anchoringZonesFileTask.Result.Id; configuration.ZoneDrawingId = zonesFileTask.Result.Id; await configurationRepository.UpdateAsync(configuration); await auditingScope.SaveAsync(); await uow.CompleteAsync(); } } }
-
0
hi
Can you test your code in the template project and share it?
I will download and check your code.
liming.ma@volosoft.com
Thanks
-
0
-
0
Great 👍