title: How to audit login in ASP.NET Core?
body: <p>hello community I am implementing a system to audit the modifications that are made in my application carry out the process that is described in this article:</p>
  <p><a href="https://codewithmukesh.com/blog/audit-trail-implementation-in-aspnet-core/?unapproved=50671&amp;moderation-hash=71700d12d4ebaf51ad9d90c4a9834324#comment-50671" rel="nofollow noreferrer">https://codewithmukesh.com/blog/audit-trail-implementation-in-aspnet-core/?unapproved=50671&amp;moderation-hash=71700d12d4ebaf51ad9d90c4a9834324#comment-50671</a></p>
  <p>but I don't know how to get the login of my application, to login I use web token and authentication provider.</p>
  <p>any suggestion how to do it? I don't know if it can be done with serilog or something similar</p>
  <p>this is my code:</p>
  <pre><code>public class Audit
  {
      public int Id { get; set; }
      public string UserId { get; set; }
      public string Type { get; set; }
      public string TableName { get; set; }
      public DateTime DateTime { get; set; }
      public string OldValues { get; set; }
      public string NewValues { get; set; }
      public string AffectedColumns { get; set; }
      public string PrimaryKey { get; set; }
  }
  
  public enum AuditType
  {
      None = 0,
      Create = 1,
      Update = 2,
      Delete = 3
  }
  
  public class AuditEntry
  {
      public AuditEntry(EntityEntry entry)
      {
          Entry = entry;
      }
      public EntityEntry Entry { get; }
      public string UserId { get; set; }
      public string TableName { get; set; }
      public Dictionary&lt;string, object&gt; KeyValues { get; } = new Dictionary&lt;string, object&gt;();
      public Dictionary&lt;string, object&gt; OldValues { get; } = new Dictionary&lt;string, object&gt;();
      public Dictionary&lt;string, object&gt; NewValues { get; } = new Dictionary&lt;string, object&gt;();
      public AuditType AuditType { get; set; }
      public List&lt;string&gt; ChangedColumns { get; } = new List&lt;string&gt;();
      public Audit ToAudit()
      {
          var audit = new Audit();
          audit.UserId = UserId;
          audit.Type = AuditType.ToString();
          audit.TableName = TableName;
          audit.DateTime = DateTime.Now;
          audit.PrimaryKey = JsonConvert.SerializeObject(KeyValues);
          audit.OldValues = OldValues.Count == 0 ? null : JsonConvert.SerializeObject(OldValues);
          audit.NewValues = NewValues.Count == 0 ? null : JsonConvert.SerializeObject(NewValues);
          audit.AffectedColumns = ChangedColumns.Count == 0 ? null : JsonConvert.SerializeObject(ChangedColumns);
          return audit;
      }
  }
  
  public abstract class AuditableIdentityContext : IdentityDbContext
  {
      public AuditableIdentityContext(DbContextOptions options) : base(options)
      {
      }
      public DbSet&lt;Audit&gt; AuditLogs { get; set; }
      public virtual async Task&lt;int&gt; SaveChangesAsync(string userId = null)
      {
          OnBeforeSaveChanges(userId);
          var result = await base.SaveChangesAsync();
          return result;
      }
      private void OnBeforeSaveChanges(string userId)
      {
          ChangeTracker.DetectChanges();
          var auditEntries = new List&lt;AuditEntry&gt;();
          foreach (var entry in ChangeTracker.Entries())
          {
              if (entry.Entity is Audit || entry.State == EntityState.Detached || entry.State == EntityState.Unchanged)
                  continue;
              var auditEntry = new AuditEntry(entry);
              auditEntry.TableName = entry.Entity.GetType().Name;
              auditEntry.UserId = userId;
              auditEntries.Add(auditEntry);
              foreach (var property in entry.Properties)
              {
                  string propertyName = property.Metadata.Name;
                  if (property.Metadata.IsPrimaryKey())
                  {
                      auditEntry.KeyValues[propertyName] = property.CurrentValue;
                      continue;
                  }
                  switch (entry.State)
                  {
                      case EntityState.Added:
                          auditEntry.AuditType = Enums.AuditType.Create;
                          auditEntry.NewValues[propertyName] = property.CurrentValue;
                          break;
                      case EntityState.Deleted:
                          auditEntry.AuditType = Enums.AuditType.Delete;
                          auditEntry.OldValues[propertyName] = property.OriginalValue;
                          break;
                      case EntityState.Modified:
                          if (property.IsModified)
                          {
                              auditEntry.ChangedColumns.Add(propertyName);
                              auditEntry.AuditType = Enums.AuditType.Update;
                              auditEntry.OldValues[propertyName] = property.OriginalValue;
                              auditEntry.NewValues[propertyName] = property.CurrentValue;
                          }
                          break;
                  }
              }
          }
          foreach (var auditEntry in auditEntries)
          {
              AuditLogs.Add(auditEntry.ToAudit());
          }
      }
  }
  </code></pre>