Audit Log Oluşturma .Net Core

Merhaba,

Bugün, .NET Core projelerinde kullanıcının gerçekleştirdiği CRUD işlemlerini takip etmek için bir Audit Log örneği oluşturacağız.

Audit Log uygulamak için, .NET Core proje bağlamında Context sınıfındaki SaveChanges() metodunu ezerek Create, Update ve Delete işlemlerini izleyebiliriz.

Haydi başlayalım!

Başlamadan Önce

Ayrıca daha fazla içeriğime ulaşmak için YouTube kanalımı ziyaret edebilirsiniz.


Örnek proje kodlarını doğrudan aşağıdaki bağlantıdan inceleyebilirsiniz:

GitHub – EmreKabali/CoreAuditLogExample


Audit Log Nasıl Uygulanır?

Audit Modeli Oluşturma

İlk olarak, veritabanındaki işlemleri saklayacak Audit modelimizi oluşturalım:

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; }
}

Bu model, ilerleyen aşamalarda yapılan değişiklikleri saklamak için kullanılacaktır.

Audit Servisi Oluşturma

Audit modelini oluştururken işlemleri tekrar etmemek için bir servis oluşturalım:

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<string, object> KeyValues { get; } = new();
    public Dictionary<string, object> OldValues { get; } = new();
    public Dictionary<string, object> NewValues { get; } = new();
    public AuditType AuditType { get; set; }
    public List<string> ChangedColumns { get; } = new();
    
    public Audit ToAudit()
    {
        return new Audit
        {
            UserId = UserId,
            Type = AuditType.ToString(),
            TableName = TableName,
            DateTime = DateTime.Now,
            PrimaryKey = JsonConvert.SerializeObject(KeyValues),
            OldValues = OldValues.Count == 0 ? "null" : JsonConvert.SerializeObject(OldValues),
            NewValues = NewValues.Count == 0 ? "null" : JsonConvert.SerializeObject(NewValues),
            AffectedColumns = ChangedColumns.Count == 0 ? "null" : JsonConvert.SerializeObject(ChangedColumns)
        };
    }
}

Bu kodda EntityEntry sınıfı, EF Core tarafından sağlanmaktadır.

Context Sınıfında SaveChanges() Ezme

Uygulama için oluşturulan Context sınıfında, SaveChanges() metodunu ezerek Audit kayıtlarını oluşturacak mantığı ekleyelim.

Öncelikle BeforeSaveChanges() adında bir metot oluşturalım:

private void BeforeSaveChanges()
{
    ChangeTracker.DetectChanges();
    var auditEntries = new List<AuditEntry>();
    
    foreach (var entry in ChangeTracker.Entries())
    {
        if (entry.Entity is Audit || entry.State is EntityState.Detached or EntityState.Unchanged)
            continue;
        
        var auditEntry = new AuditEntry(entry)
        {
            TableName = entry.Entity.GetType().Name
        };
        
        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 = AuditType.Create;
                    auditEntry.NewValues[propertyName] = property.CurrentValue;
                    auditEntry.UserId = entry.Property("CreatedBy")?.CurrentValue?.ToString() ?? "Null";
                    break;
                case EntityState.Deleted:
                    auditEntry.AuditType = AuditType.Delete;
                    auditEntry.OldValues[propertyName] = property.OriginalValue;
                    auditEntry.UserId = entry.Property("LastModifiedBy")?.CurrentValue?.ToString() ?? "Null";
                    break;
                case EntityState.Modified:
                    if (property.IsModified)
                    {
                        auditEntry.ChangedColumns.Add(propertyName);
                        auditEntry.AuditType = AuditType.Update;
                        auditEntry.OldValues[propertyName] = property.OriginalValue;
                        auditEntry.NewValues[propertyName] = property.CurrentValue;
                        auditEntry.UserId = entry.Property("LastModifiedBy")?.CurrentValue?.ToString() ?? "Null";
                    }
                    break;
            }
        }
    }
    
    foreach (var auditEntry in auditEntries)
    {
        AuditLogs.Add(auditEntry.ToAudit());
    }
}

SaveChanges() Metodunu Ezme

public override int SaveChanges()
{
    BeforeSaveChanges();
    return base.SaveChanges();
}

public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
    BeforeSaveChanges();
    return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}

Sonuç

Tebrikler!

Bu işlemler başarıyla tamamlandığında, Audit tablosuna şu şekilde kayıtlar eklenmiş olacaktır:

Output:

| Id | UserId | Type   | TableName | DateTime | OldValues | NewValues |
|----|--------|--------|-----------|----------|-----------|-----------|
| 1  | 12345  | Create | Orders    | 2025-03-13 | null | {"Amount":100} |

Örnek projenin kaynak kodlarını aşağıdaki GitHub deposunda bulabilirsiniz:

GitHub – EmreKabali/CoreAuditLogExample

Umarım faydalı olmuştur!

More Reading

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *