I am quite new to ASP.NET Core. I want to create ASP.NET Core 2.2 WebAPI, with Entity Framework Core and ASP.NET Identity. Also, I want to use JWT to secure access to that WebAPI with tokens.
I have successfully managed to insert user to DB and to get token back from my API, and token auth is working.
But, I also want to soft delete database records and to keep track on who has deleted/updated/added a record.
Test table for that is Countries, where fields are only Title
and Description
.
So far, I have turned Internet upside-down, but no help :(
Las thing that I have tried is (userId is null
):
In startup.cs:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
in my AppDbContext.cs
public class AppDbContext : IdentityDbContext<AppUser>{
public AppDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<AppUser> AppUsers { get; set; }
public DbSet<Country> Countries { get; set; } // just for testing
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// TODO - IGNORE THIS
//builder.Entity<AppUser>().Property<bool>("IsDeleted");
//builder.Entity<AppUser>().HasQueryFilter(m => EF.Property<bool>(m, "IsDeleted") == false);
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
CheckBeforeSaving();
return (await base.SaveChangesAsync(true, cancellationToken).ConfigureAwait(false));
}
private void CheckBeforeSaving()
{
var httpContextAccessor = this.GetService<IHttpContextAccessor>();
var userId = httpContextAccessor?.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
foreach (var entry in ChangeTracker.Entries())
{
switch (entry.State)
{
case EntityState.Detached:
break;
case EntityState.Unchanged:
break;
case EntityState.Deleted:
entry.State = EntityState.Modified;
entry.CurrentValues["IsDeleted"] = true;
entry.CurrentValues["DeletedBy"] = userId;
entry.CurrentValues["Deleted"] = DateTime.Now;
break;
case EntityState.Modified:
entry.CurrentValues["UpdatedBy"] = userId;
entry.CurrentValues["Updated"] = DateTime.Now;
break;
case EntityState.Added:
entry.CurrentValues["IsDeleted"] = false;
entry.CurrentValues["CreatedBy"] = userId;
entry.CurrentValues["Created"] = DateTime.Now;
entry.CurrentValues["Description"] = userId;
break;
default:
break;
}
}
}}}
Try to inject IHttpContextAccessor
into the ApplicationDbContext
directly:
public class ApplicationDbContext : IdentityDbContext<AppUser>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IHttpContextAccessor httpContextAccessor)
: base(options)
{
_httpContextAccessor= httpContextAccessor;
}
//other methods
private void CheckBeforeSaving()
{
var userId = _httpContextAccessor?.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
//...
}
}