EfCore.AuditTrail 1.0.0

Additional Details

Sorry team, this package has one critical bug which I am currently working on. I will release another version soon.

dotnet add package EfCore.AuditTrail --version 1.0.0
                    
NuGet\Install-Package EfCore.AuditTrail -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EfCore.AuditTrail" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EfCore.AuditTrail" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="EfCore.AuditTrail" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EfCore.AuditTrail --version 1.0.0
                    
#r "nuget: EfCore.AuditTrail, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EfCore.AuditTrail@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EfCore.AuditTrail&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=EfCore.AuditTrail&version=1.0.0
                    
Install as a Cake Tool

EfCore.AuditTrail

NuGet License Build

Zero-config audit trails for EF Core. Automatically stamps every entity write with who did it, when, and what changed.

The Problem

You've written this code in every project:

  • Manual CreatedAt, UpdatedAt timestamp logic
  • Current user resolution from HttpContext
  • SaveChanges overrides for audit logging
  • Serialization of old/new values to a log table

The Solution

One line. Never write it again.

builder.Services.AddAuditTrail();

Install

dotnet add package EfCore.AuditTrail

Quick Start

1. Register the service

var builder = WebApplicationBuilder.CreateBuilder(args);

builder.Services.AddAuditTrail();
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(conn).AddAuditTrail()
);

var app = builder.Build();

2. Add audit fields to your entities

No base class required. Just declare the properties by convention:

public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    // These are automatically stamped by the interceptor
    public DateTime CreatedAt { get; set; }
    public string? CreatedBy { get; set; }
    public DateTime UpdatedAt { get; set; }
    public string? UpdatedBy { get; set; }
}

3. Done

Every insert, update, or delete is now:

  • Automatically timestamped
  • User-attributed (resolved from HttpContext claims)
  • Logged with full before/after snapshots in AuditLogs table
var product = new Product { Name = "Widget", Price = 9.99m };
await db.Products.AddAsync(product);
await db.SaveChangesAsync();

// Audit log automatically created:
// {
//   "Id": "abc-123",
//   "TableName": "Products",
//   "Operation": "Insert", 
//   "NewValues": {"Name":"Widget","Price":9.99},
//   "OldValues": null,
//   "UserId": "user-456",
//   "UserName": "John Doe",
//   "Timestamp": "2026-03-26T10:30:00Z"
// }

Querying Audit Logs

// All changes to Products
var logs = await db.AuditLogs()
    .ForTable<Product>()
    .OrderByNewest()
    .ToListAsync();

// Changes by a specific user
var userChanges = await db.AuditLogs()
    .ByUser("user-456")
    .InRange(start, end)
    .ToListAsync();

// Only update operations
var updates = await db.AuditLogs()
    .WithOperation(AuditOperation.Update)
    .ToListAsync();

Features

✅ Zero Configuration — No base classes, no interfaces, no overrides
✅ Convention-based — Just declare CreatedAt, UpdatedAt, CreatedBy, UpdatedBy
✅ Full Change History — Old values, new values, changed columns, timestamps
✅ User Attribution — Automatically resolves current user from HttpContext
✅ Multi-tenant Support — Include TenantId property for automatic isolation
✅ Soft Delete Support — Use [SoftDelete] attribute for logical deletes
✅ Queryable Audit Logs — LINQ-friendly helpers for filtering and sorting
✅ Multi-framework — Targets .NET 6, 7, 8, 9

Options

builder.Services.AddAuditTrail(options =>
{
    options.SystemUserName = "system";        // Default user when none authenticated
    options.EnableSoftDelete = true;           // Support [SoftDelete] attribute
    options.StoreIpAddress = false;            // Store client IP in audit logs
    options.AuditTableName = "AuditLogs";      // Custom table name
});

Custom User Provider

For non-web contexts (background jobs, CLI), implement ICurrentUserProvider:

public class CustomUserProvider : ICurrentUserProvider
{
    public AuditUser? GetCurrentUser()
    {
        // Resolve from your own source
        return new AuditUser("job-service", "Background Job");
    }
}

builder.Services.AddScoped<ICurrentUserProvider, CustomUserProvider>();

Skip Properties

Exclude sensitive or high-cardinality properties:

public class User
{
    public Guid Id { get; set; }
    public string Email { get; set; }
    
    [AuditIgnore]
    public string PasswordHash { get; set; }  // Not logged
}

Soft Delete

Mark entities for logical (soft) deletes:

[SoftDelete]
public class Document
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public DateTime DeletedAt { get; set; }
    public string? DeletedBy { get; set; }
}

// Deletes are logged, entity not physically removed
var doc = await db.Documents.FindAsync(id);
db.Documents.Remove(doc);
await db.SaveChangesAsync();  // Soft-deleted, tracked in audit log

Supported Databases

  • ✅ SQL Server (2016+)
  • ✅ PostgreSQL (10+)
  • ✅ MySQL (5.7+)
  • ✅ SQLite (3.0+)

How It Works

EfCore.AuditTrail uses EF Core's SaveChangesInterceptor:

  1. Before SaveChanges — Snapshots all pending changes (old/new values)
  2. Stamp Audit Fields — Sets CreatedAt/UpdatedAt/By by convention
  3. After SaveChanges — Writes AuditEntry rows to AuditLogs table (now with PKs for inserts)

No reflection on every query, no runtime proxies—just interception at the save boundary.

Testing

dotnet test

The test suite includes:

  • Insert/Update/Delete audit logging
  • Timestamp convention stamping
  • User provider integration
  • Property snapshotting
  • Query extension helpers

Contributing

We welcome contributions!

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -am 'Add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request

License

EfCore.AuditTrail is licensed under the MIT License. See LICENSE for details.

Support


Built with ❤️ by Sourav Pal

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 174 3/26/2026 1.0.0 is deprecated because it has critical bugs.