How To Track Entity Changes With EF Core | Audit Logging | AuditSharp
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 AuditSharp
otomatik olarak veritabanınıza erişir ve gerekli tüm geçişleri uygular.
AuditSharp
, tüm SaveChanges
adı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.