How To Track Entity Changes With EF Core | Audit Logging | AuditSharp

Furkan Güngör
3 min readDec 16, 2024

Audit log, sistemlerde yapılan değişikliklerin kaydını tutmak için kullanılan bir mekanizmadır. Kullanıcı işlemlerini izlemek, veri manipülasyonlarını takip etmek ve gerektiğinde hataları geri izlemek için kritik bir öneme sahiptir. Entity Framework Core (EF Core) ile bu süreci kolaylaştırmak için SaveChanges Interceptor mekanizmasından yararlanabiliriz. Bu makalede, EF Core ile PostgreSQL kullanan bir uygulamada audit log tutmayı adım adım inceleyeceğiz.

NuGet Paketleri

Projeye EF Core ve PostgreSQL desteği eklemek için aşağıdaki NuGet paketlerini yükleyin:

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Npgsql.EntityFrameworkCore.PostgreSQL

Veritabanı Bağlantısı

EF Core ile PostgreSQL bağlantısını kurmak için appsettings.json dosyasına aşağıdaki gibi bir yapı ekleyin:

{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=AuditLogDb;Username=postgres;Password=yourpassword"
}
}
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }

public DbSet<YourEntity> YourEntities { get; set; }
public DbSet<AuditLog> AuditLogs { get; set; }
}

Değişiklikleri izlemek ve kaydetmek için aşağıdaki bilgileri kullanabiliriz.

  • Id
  • TableName
  • Action
  • PrimaryKey
  • OldValues
  • NewValues
  • Timestamp
  • UserId
public class AuditLog
{
public int Id { get; set; }
public string TableName { get; set; }
public string Action { get; set; } // Insert, Update, Delete
public string PrimaryKey { get; set; }
public string OldValues { get; set; } // JSON formatında eski değerler
public string NewValues { get; set; } // JSON formatında yeni değerler
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
public string UserId { get; set; } // İşlemi yapan kullanıcı
}

SaveChanges Interceptor

public class AuditLogInterceptor : SaveChangesInterceptor
{
private readonly IHttpContextAccessor _httpContextAccessor;

public AuditLogInterceptor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

public override ValueTask<int> SaveChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
{
var context = eventData.Context;
if (context == null) return base.SaveChangesAsync(eventData, result, cancellationToken);

var auditLogs = new List<AuditLog>();
var entries = context.ChangeTracker.Entries().Where(e => e.State is EntityState.Added or EntityState.Modified or EntityState.Deleted);

foreach (var entry in entries)
{
var auditLog = new AuditLog
{
TableName = entry.Entity.GetType().Name,
Action = entry.State.ToString(),
PrimaryKey = entry.Properties.FirstOrDefault(p => p.Metadata.IsPrimaryKey())?.CurrentValue?.ToString(),
OldValues = entry.State == EntityState.Modified ? JsonConvert.SerializeObject(entry.OriginalValues.Properties.ToDictionary(p => p.Name, p => entry.OriginalValues[p.Name])) : null,
NewValues = entry.State is EntityState.Added or EntityState.Modified ? JsonConvert.SerializeObject(entry.CurrentValues.Properties.ToDictionary(p => p.Name, p => entry.CurrentValues[p.Name])) : null,
UserId = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value
};

auditLogs.Add(auditLog);
}

context.Set<AuditLog>().AddRange(auditLogs);
return base.SaveChangesAsync(eventData, result, cancellationToken);
}
}

AuditLogInterceptor içerisinde yazdığımız kodlar SaveChanges komutundan önce çalışacaktır. Eğer sonra çalışmasını istiyorsanız SavedChanges ve SavedChangesAsync metotlarını override edebilirsiniz.

AuditLogInterceptor çalışabilmesi için AddInterceptors metodunu kullanmalısınız.

builder.Services.AddDbContext<PostgreSqlSampleDbContext>(options => options.UseNpgsql("your_connection_string").AddInterceptors(new AuditLogInterceptor(new HttpContextAccessor())));

İşte bu kadar artık tüm değişiklikler de oldValues ve newValues gibi verilere sahip olabilirsiniz ancak daha basit bir yöntem var. 🚀🥳

AuditSharp

AuditSharp, .NET uygulamalarındaki audio işlemlerine yönelik lightweight bir kütüphanedir. Değişiklikleri izlemeyi, meta verileri kaydetmeyi ve uygulamanızda audio izlerini saklamayı basitleştirir. Yazının bu bölümünde, AuditSharp’ı projenize nasıl entegre edeceğiniz ve kullanacağınız konusunda adım adım rehberlik sağlayacağım. 🚀🥳

Installation

Başlamak için AuditSharp kütüphanesini NuGet üzerinden yükleyin:

dotnet add package AuditSharp.PostgreSql

Configuration

Program.cs içerisinde DbContext sınıflarını genellikle register ederiz. Bu kısımda RegisterAuditSharp metodunu kullanmanız yeterli olacaktır.

builder.Services.AddDbContext<YourDbContext>(options => options.UseNpgsql("your_connection_string").RegisterAuditSharp());

AuditSharp şimdilik PostgreSql üzerinde çalışır. Uygulamanızın çalıştığı veri tabanına veya başka bir veri tabanına kurabilirsiniz. Yapmanız gereken tek şey AddAuditSharp metodunu configure etmek.

builder.Services.AddAuditSharp(options =>
{
options.UseNpgsql("your_connection_string");
});

AuditSharp gerekli olan bütün migration dosyalarını kendi içinde saklar. Migrationların otomatik olarak uygulanması için aşağıdaki kodu eklemeyi unutmayın.

app.UseAuditSharp();

Artık her şey hazır. ✅

Uygulamanız çalıştığında AuditSharpotomatik olarak veritabanınıza erişir ve gerekli tüm geçişleri uygular.

AuditSharp, tüm SaveChangesadımlarını izler ve bunları audit-sharpşeması içindeki tablosuna kaydeder.

Değişiklikleri takip etmek için tabloyu kontrol edebilirsiniz.

Örneğin Ekleme, Güncelleme ve Silme işlemlerinde kaydedilen loglar aşağıdaki gibidir;

AuditSharp henüz ilk adımlarını atıyor. 🐣

Bu sebeple aradığınız her şeyi bu kütüphane içerisinde bulamayabilirsiniz. 💔

Ancak gelecekte yeni özellikler eklemeyi planlıyorum;

  • Advanced filter on AuditLog
  • Ignore entity or field
  • Log Dashboard
  • Detection of changing ares on AuditLog
  • Sql Server Support
  • MariaDb Support

ve daha fazlası.

Eğer beğendiyseniz ve ben bu özelliklerin geliştirilmesinde katkı sağlarım diyorsanız aşağıdaki linke tıklayarak kütüphaneyi inceleyebilirsiniz. 🧐

Bu yazıda hem yeni geliştirdiğim kütüphanenin reklamını hem de bu bahaneyle EF Core üzerinde bulunan Interceptor özelliği ile neler yapabileceğimizi anlatmış oldum. 🎉

Umarım faydalı olmuştur.

--

--

Furkan Güngör
Furkan Güngör

Written by Furkan Güngör

Solution Developer — I want to change the world, give me the source code.

Responses (2)