In ASP.NET Core-6 Web API, I am implementing Entity Framework and ASP.NET Identity Db Context.
I have these services.
Interface:
public interface ICurrentUserService
{
public string UserId { get; }
public string UserName { get; }
}
Implementation:
public class CurrentUserService : ICurrentUserService
{
public string UserId { get; }
public string UserName { get; }
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
UserName = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}
}
Then I called it in ApplicationDbContext as shown below.
ApplicationDbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserClaim<string>,ApplicationUserRole, IdentityUserLogin<string>,IdentityRoleClaim<string>, IdentityUserToken<string>>
{
private readonly ICurrentUserService _currentUserService;
private readonly IDateTime _dateTime;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options,
ICurrentUserService currentUserService, IDateTime dateTime)
: base(options)
{
_currentUserService = currentUserService;
_dateTime = dateTime;
}
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<ApplicationRole> ApplicationRoles { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
base.OnModelCreating(builder);
builder.ApplyConfiguration(new ApplicationUserConfigurations());
builder.ApplyConfiguration(new ApplicationUserRoleConfigurations());
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
foreach (var item in ChangeTracker.Entries<AuditableEntity>())
{
switch (item.State)
{
case EntityState.Modified:
item.Entity.LastModifiedBy = _currentUserService?.UserName;
item.Entity.LastModifiedAt = DateTime.Now;
break;
case EntityState.Added:
item.Entity.CreatedBy = _currentUserService?.UserName;
item.Entity.CreatedAt = DateTime.Now;
break;
case EntityState.Deleted:
item.Entity.DeletedBy = _currentUserService?.UserName;
item.Entity.DeletedAt = DateTime.Now;
item.Entity.IsDeleted = true;
break;
default:
break;
}
}
return await base.SaveChangesAsync(cancellationToken);
}
public override int SaveChanges()
{
OnBeforeSaveChanges(_currentUserService?.UserName);
foreach (var item in ChangeTracker.Entries<AuditableEntity>())
{
switch (item.State)
{
case EntityState.Modified:
item.Entity.LastModifiedBy = _currentUserService?.UserName;
item.Entity.LastModifiedAt = DateTime.Now;
break;
case EntityState.Added:
item.Entity.CreatedBy = _currentUserService?.UserName;
item.Entity.CreatedAt = DateTime.Now;
break;
case EntityState.Deleted:
item.Entity.DeletedBy = _currentUserService?.UserName;
item.Entity.DeletedAt = DateTime.Now;
item.Entity.IsDeleted = true;
break;
default:
break;
}
}
return base.SaveChanges();
}
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _dbContext;
public UnitOfWork(
ApplicationDbContext dbContext,
UserManager<ApplicationUser> userManager
)
{
_dbContext = dbContext;
_userManager = userManager;
}
public async Task Save()
{
await _dbContext.SaveChangesAsync();
}
}
In the application, when I implement it as:
await _unitOfWork.Employees.InsertAsync(bankUser);
await _unitOfWork.Save();
I expected it to also insert UserName in the CreatedBy field, but it is null.
But If I implement it directly as :
_currentUserService.UserName
inside the application, it works..
What could be wrong and how do I correct this?
Thanks
HttpContextis present otherwise it will be null.