[英]ASP.NET Core Web API - How to implement Current UserName in SaveChangesAsync on ApplicationDbContext
In ASP.NET Core-6 Web API, I am implementing Entity Framework and ASP.NET Identity Db Context.在 ASP.NET Core-6 Web API 中,我正在实现实体框架和 Z9E0DA8438E1E38A1DDZCE Db 4
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 中调用它,如下所示。
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.我希望它也会在 CreatedBy 字段中插入用户名,但它是 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谢谢
I think the problem is that you assign UserName
and UserId
right away when the service is constructed.我认为问题在于您在构建服务时立即分配了UserName
和UserId
。 At the time of the construction of your service there might not be a HttpContext
to work with.在构建服务时,可能没有HttpContext
可以使用。
Try using the HttpContextAccessor
in your getter like this:尝试在你的 getter 中使用HttpContextAccessor
,如下所示:
public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public string UserName => this.httpContextAccessor.HttpContext?.User?.Identity?.Name;
public string UserId => this.httpContextAccessor.HttpContext?.User?.Claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
}
By using the HttpContextAccessor
when the property is accessed you make sure to get the currently valid one (if there is any).通过在访问属性时使用HttpContextAccessor
,您可以确保获取当前有效的(如果有的话)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.