简体   繁体   English

ASP.NET 内核 Web API - 如何在 ApplicationDbContext 上的 SaveChangesAsync 中实现当前用户名

[英]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.我认为问题在于您在构建服务时立即分配了UserNameUserId 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.

相关问题 如何将ApplicationDbContext绑定到ASP.Net Core 2.2中的View - How to bind ApplicationDbContext to a View in ASP.Net Core 2.2 如何在类/单独线程ASP.Net Core中使用ApplicationDbContext - How to use ApplicationDbContext in a Class / Separate Thread ASP.Net Core 在 ASP.NET Core 中处理 ApplicationDbContext - Dispose ApplicationDbContext in ASP.NET Core 如何在ASP.NET Web API项目中使用另一个项目的ApplicationDbContext? - How to use an ApplicationDbContext from another project in a ASP.NET web API project? 在 ASP.NET Core 5.0 Web API 中实现 DelegatingHandler? - Implement DelegatingHandler in ASP.NET Core 5.0 Web API? 如何在ASP.NET Web API Core应用程序上使用QUARTZ实现调度程序? - How to implement a scheduler using QUARTZ on an ASP.NET Web API Core application? 如何使用AddMvcCore()实现“纯”ASP.NET Core Web API - How to implement a “pure” ASP.NET Core Web API by using AddMvcCore() 我们什么时候可以在 ASP NET WEB API CORE 中使用 AddAsync 和 SaveChangesAsync - When can we use AddAsync and SaveChangesAsync in ASP NET WEB API CORE 如何在 ASP.NET CORE 3.1 Web API 中捕获当前状态码 - How to capture current Status code in ASP.NET CORE 3.1 Web API 如何在 ASP.NET CORE WEB API 中实现多对多关系 - How to implement many to many relationship in ASP.NET CORE WEB API
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM