- ABP Framework version: v9.1.1
- UI Type: Angular
- Database System: EF Core
Hello, I need a way to listen for changes to an AbpUser’s Name and Surname.
I tried using ILocalEventHandler<EntityUpdatedEventData<IdentityUser>>, but the problem is that this handler doesn’t provide the previous values. Because of that, there’s no way to compare the old and new values to determine whether the name actually changed.
Is there another way to handle this?
1 Answer(s)
-
0
- Solution
- Use EF Core ChangeTracker inside a domain event handler (or a SaveChanges interceptor) to read original values. ABP’s EntityUpdatedEventData<T> doesn’t carry old values by design, but you can access EF Core’s OriginalValues and compare.
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EventBus.Local; using Volo.Abp.Identity; public class IdentityUserUpdatedHandler : ILocalEventHandler<EntityUpdatedEventData<IdentityUser>> { private readonly IDbContextProvider<IIdentityDbContext> _dbContextProvider; // or your unified DbContext provider public IdentityUserUpdatedHandler(IDbContextProvider<IIdentityDbContext> dbContextProvider) { _dbContextProvider = dbContextProvider; } public async Task HandleEventAsync(EntityUpdatedEventData<IdentityUser> eventData) { // Ensure we are in the same UoW/DbContext where the change is tracked var dbContext = await _dbContextProvider.GetDbContextAsync(); // Get the tracked Entry for this entity var entry = dbContext.Entry(eventData.Entity); if (entry.State != EntityState.Modified) { // Not tracked or not modified in this context return; } // Read original and current values var originalName = entry.OriginalValues[nameof(IdentityUser.Name)]?.ToString(); var currentName = entry.CurrentValues[nameof(IdentityUser.Name)]?.ToString(); var originalSurname = entry.OriginalValues[nameof(IdentityUser.Surname)]?.ToString(); var currentSurname = entry.CurrentValues[nameof(IdentityUser.Surname)]?.ToString(); var nameChanged = !string.Equals(originalName, currentName, StringComparison.Ordinal); var surnameChanged = !string.Equals(originalSurname, currentSurname, StringComparison.Ordinal); if (nameChanged || surnameChanged) { // Your logic here (publish another event, call a service, etc.) } } }Notes:
Inject the IDbContextProvider for the DbContext that tracks IdentityUser (e.g., your unified AppDbContext if you call builder.ConfigureIdentity()).
This handler must run within the same Unit of Work as the update so the Entry has OriginalValues. ABP’s auto entity events are published in the same UoW as of v5+, so this works when your update happens via repositories/UoW.
Alternative: EF Core SaveChanges interceptor If you prefer not to rely on the local event to get original values, you can implement an interceptor that always has access to ChangeTracker before saving:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Volo.Abp.Identity; public class UserNameChangeInterceptor : SaveChangesInterceptor { public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result) { var context = eventData.Context; if (context == null) return base.SavingChanges(eventData, result); foreach (var entry in context.ChangeTracker.Entries<IdentityUser>().Where(e => e.State == EntityState.Modified)) { var originalName = entry.OriginalValues[nameof(IdentityUser.Name)]?.ToString(); var currentName = entry.CurrentValues[nameof(IdentityUser.Name)]?.ToString(); var originalSurname = entry.OriginalValues[nameof(IdentityUser.Surname)]?.ToString(); var currentSurname = entry.CurrentValues[nameof(IdentityUser.Surname)]?.ToString(); if (!string.Equals(originalName, currentName, StringComparison.Ordinal) || !string.Equals(originalSurname, currentSurname, StringComparison.Ordinal)) { // Your logic here } } return base.SavingChanges(eventData, result); } }Register the interceptor in your DbContextOptions during module ConfigureServices.
- Why not use audit logs? ABP’s audit logging can record entity change sets including old/new property values, but it’s intended for logging. If you need runtime logic when Name/Surname changes, the ChangeTracker approach is the correct, supported way.
- Sources
- GitHub: ABP Framework repository (entity events and UoW behavior referenced in migration notes)
- https://github.com/abpframework/abp
- ABP Migration Guide note about entity events being in the same UoW (supports accessing ChangeTracker in handlers)
- https://abp.io/docs/latest/release-info/migration-guides/abp-5-0 (validated via internal context)
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.