AuditaX 2.4.1

Requires NuGet 6.0 or higher.

dotnet add package AuditaX --version 2.4.1
                    
NuGet\Install-Package AuditaX -Version 2.4.1
                    
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="AuditaX" Version="2.4.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AuditaX" Version="2.4.1" />
                    
Directory.Packages.props
<PackageReference Include="AuditaX" />
                    
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 AuditaX --version 2.4.1
                    
#r "nuget: AuditaX, 2.4.1"
                    
#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 AuditaX@2.4.1
                    
#: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=AuditaX&version=2.4.1
                    
Install as a Cake Addin
#tool nuget:?package=AuditaX&version=2.4.1
                    
Install as a Cake Tool

AuditaX Logo

AuditaX

Flexible Entity Audit Logging for .NET 10+

NuGetLicenseC#.NET

AuditaX is a modern, extensible audit logging library for .NET applications. It provides a unified approach to tracking entity changes across different ORMs and database providers, with support for both automatic and manual audit control.

Built exclusively for .NET 10 with C# 14, AuditaX offers fluent configuration, multiple serialization formats, and seamless integration with your existing data access layer.


💖 Support the Project

AuditaX is a passion project, driven by the desire to provide a truly modern audit logging solution for the .NET community. Maintaining this library requires significant effort: staying current with each .NET release, addressing issues promptly, implementing new features, keeping documentation up to date, and ensuring compatibility across different ORMs and database providers.

If AuditaX has helped you build better applications or saved you development time, I would be incredibly grateful for your support. Your contribution—no matter the size—helps me dedicate time to respond to issues quickly, implement improvements, and keep the library evolving alongside the .NET platform.

I'm also looking for sponsors who believe in this project's mission. Sponsorship helps ensure AuditaX remains actively maintained and continues to serve the .NET community for years to come.

Of course, there's absolutely no obligation. If you prefer, simply starring the repository or sharing AuditaX with fellow developers is equally appreciated!

  • ⭐ Star the repository on GitHub to raise its visibility

  • 💬 Share AuditaX with your team or community

  • ☕ Support via Donations:

    • PayPal
    • Ko-fi

✨ Features

  • Multiple ORM Support: Dapper and Entity Framework Core
  • Multiple Database Providers: SQL Server and PostgreSQL
  • Flexible Change Log Format: JSON or XML serialization
  • Automatic Change Tracking: EF Core interceptors capture all changes
  • Manual Audit Control: IAuditUnitOfWork for Dapper repositories
  • Related Entities: Track child entity changes under parent audit log
  • Lookup Properties: Resolve FK values to display names (e.g., RoleId → "Administrator")
  • Configuration Options: appsettings.json or Fluent API
  • Auto Table Creation: Creates audit table on startup if needed
  • Startup Validation: Validates table structure and configuration

🎉 What's New in 2.0.0

Breaking change: IAuditQueryService, Response<T>, PagedResponse<T>, AuditQueryMessages, AuditQueryValidator, and all query models have been removed. AuditaX now focuses exclusively on audit registration. Querying the AuditLog table is the consumer's responsibility.

See CHANGELOG.md for the full migration guide.


📦 Packages

Package Description NuGet
AuditaX Core library with interfaces and base services NuGet
AuditaX.Dapper Dapper ORM support with IAuditUnitOfWork NuGet
AuditaX.EntityFramework EF Core support with automatic interceptors NuGet
AuditaX.SqlServer SQL Server database provider NuGet
AuditaX.PostgreSql PostgreSQL database provider NuGet

🚀 Getting Started

Installation

Choose packages based on your ORM and database:

For Dapper + SQL Server:

dotnet add package AuditaX
dotnet add package AuditaX.Dapper
dotnet add package AuditaX.SqlServer

For EF Core + PostgreSQL:

dotnet add package AuditaX
dotnet add package AuditaX.EntityFramework
dotnet add package AuditaX.PostgreSql

Configuration

Option A: appsettings.json
{
  "AuditaX": {
    "TableName": "AuditLog",
    "Schema": "dbo",
    "LogFormat": "Json",
    "AutoCreateTable": true,
    "EnableLogging": true,
    "Entities": {
      "Product": {
        "Key": "Id",
        "Properties": [ "Name", "Price", "Stock" ]
      }
    }
  }
}
services.AddAuditaX(configuration)
    .UseDapper<DapperContext>()
    .UseSqlServer()
    .ValidateOnStartup();
Option B: Fluent API
services.AddAuditaX(options =>
{
    options.TableName = "AuditLog";
    options.Schema = "dbo";
    options.AutoCreateTable = true;
    options.EnableLogging = true;
    options.LogFormat = LogFormat.Json;

    options.ConfigureEntity<Product>("Product")
        .WithKey(p => p.Id)
        .Properties("Name", "Price", "Stock");
})
.UseDapper<DapperContext>()
.UseSqlServer()
.ValidateOnStartup();

💻 Usage

With Dapper (Manual Audit)

Inject IAuditUnitOfWork into your repositories:

public class ProductRepository(DapperContext context, IAuditUnitOfWork audit)
{
    public async Task<int> CreateAsync(Product product)
    {
        using var connection = context.CreateConnection();
        const string sql = "INSERT INTO Products (...) OUTPUT INSERTED.ProductId VALUES (...)";

        var id = await connection.QuerySingleAsync<int>(sql, product);
        product.ProductId = id;

        await audit.LogCreateAsync(product);

        return id;
    }

    public async Task<int> UpdateAsync(Product original, Product updated)
    {
        using var connection = context.CreateConnection();
        const string sql = "UPDATE Products SET ... WHERE ProductId = @ProductId";

        var affected = await connection.ExecuteAsync(sql, updated);

        if (affected > 0)
        {
            await audit.LogUpdateAsync(original, updated);
        }

        return affected;
    }

    public async Task<bool> DeleteAsync(Product product)
    {
        using var connection = context.CreateConnection();
        const string sql = "DELETE FROM Products WHERE ProductId = @ProductId";

        var affected = await connection.ExecuteAsync(sql, new { product.ProductId });

        if (affected > 0)
        {
            await audit.LogDeleteAsync(product);
        }

        return affected > 0;
    }

    // Related entity operations
    public async Task AddTagAsync(Product product, ProductTag tag)
    {
        using var connection = context.CreateConnection();
        const string sql = "INSERT INTO ProductTags (ProductId, Tag) VALUES (@ProductId, @Tag)";

        await connection.ExecuteAsync(sql, tag);
        await audit.LogRelatedAddedAsync(product, tag);
    }

    public async Task UpdateTagAsync(Product product, ProductTag original, ProductTag modified)
    {
        using var connection = context.CreateConnection();
        const string sql = "UPDATE ProductTags SET Tag = @Tag WHERE Id = @Id";

        await connection.ExecuteAsync(sql, modified);
        await audit.LogRelatedUpdatedAsync(product, original, modified);
    }

    public async Task RemoveTagAsync(Product product, ProductTag tag)
    {
        using var connection = context.CreateConnection();
        const string sql = "DELETE FROM ProductTags WHERE Id = @Id";

        await connection.ExecuteAsync(sql, new { tag.Id });
        await audit.LogRelatedRemovedAsync(product, tag);
    }
}

With Entity Framework Core (Automatic)

EF Core uses interceptors for automatic audit logging. Configure AuditaX first, then register your DbContext with the interceptor:

Step 1: Configure AuditaX

// Configure AuditaX BEFORE registering DbContext
services.AddAuditaX(options =>
{
    options.TableName = "AuditLog";
    options.Schema = "dbo";
    options.AutoCreateTable = true;
    options.LogFormat = LogFormat.Json;

    options.ConfigureEntity<Product>("Product")
        .WithKey(p => p.Id)
        .Properties("Name", "Price", "Stock");
})
.UseEntityFramework<AppDbContext>()
.UseSqlServer()
.ValidateOnStartup();

Step 2: Register DbContext with AuditaX

// IMPORTANT: Use (sp, options) to access the service provider
services.AddDbContext<AppDbContext>((sp, options) =>
{
    options.UseSqlServer(connectionString);

    // This line enables automatic audit logging
    options.UseAuditaX(sp);
});

Note: The call to UseAuditaX(sp) is required for automatic change tracking. Without it, entity changes will not be audited.

Important: AuditaX requires EF Core's ChangeTracker to detect entity changes. Do NOT use QueryTrackingBehavior.NoTracking in your DbContext, as this disables change tracking and AuditaX will not be able to audit entity modifications.

Step 3: Use your DbContext normally

// Entity changes are automatically tracked - no manual logging needed!
var product = new Product { Name = "Widget", Price = 9.99m };
dbContext.Products.Add(product);
await dbContext.SaveChangesAsync(); // Audit log created automatically

product.Price = 12.99m;
await dbContext.SaveChangesAsync(); // Update audit log created automatically

🗄️ Audit Log Structure

SQL Server

Column JSON Format XML Format
LogId UNIQUEIDENTIFIER UNIQUEIDENTIFIER
SourceName NVARCHAR(64) NVARCHAR(64)
SourceKey NVARCHAR(64) NVARCHAR(64)
AuditLog NVARCHAR(MAX) XML

PostgreSQL

Column JSON Format XML Format
log_id UUID UUID
source_name VARCHAR(64) VARCHAR(64)
source_key VARCHAR(64) VARCHAR(64)
audit_log JSONB XML

📋 Change Log Formats

JSON Format

{
  "auditLog": [
    {
      "action": "Created",
      "user": "demo@auditax.sample",
      "timestamp": "2025-12-11T12:55:38.4907999Z"
    },
    {
      "action": "Updated",
      "user": "demo@auditax.sample",
      "timestamp": "2025-12-11T12:55:38.6169691Z",
      "fields": [
        { "name": "Price", "before": "79.99", "after": "69.99" },
        { "name": "Stock", "before": "100", "after": "95" }
      ]
    },
    {
      "action": "Added",
      "user": "demo@auditax.sample",
      "timestamp": "2025-12-11T12:55:38.6777639Z",
      "related": "ProductTag",
      "fields": [
        { "name": "Tag", "value": "Gaming" }
      ]
    },
    {
      "action": "Removed",
      "user": "demo@auditax.sample",
      "timestamp": "2025-12-11T12:55:38.7375026Z",
      "related": "ProductTag",
      "fields": [
        { "name": "Tag", "value": "Gaming" }
      ]
    },
    {
      "action": "Deleted",
      "user": "demo@auditax.sample",
      "timestamp": "2025-12-11T12:55:38.7575026Z"
    }
  ]
}

XML Format

<AuditLog>
  <Entry Action="Created" User="demo@auditax.sample" Timestamp="2025-12-12T14:38:01.9671416Z" />
  <Entry Action="Updated" User="demo@auditax.sample" Timestamp="2025-12-12T14:41:12.5715243Z">
    <Field Name="Price" Before="9.99" After="12.99" />
    <Field Name="Stock" Before="100" After="85" />
  </Entry>
  <Entry Action="Added" User="demo@auditax.sample" Timestamp="2025-12-12T14:42:00.1234567Z" Related="ProductTag">
    <Field Name="Tag" Value="Gaming" />
  </Entry>
  <Entry Action="Removed" User="demo@auditax.sample" Timestamp="2025-12-12T14:43:00.1234567Z" Related="ProductTag">
    <Field Name="Tag" Value="Gaming" />
  </Entry>
  <Entry Action="Deleted" User="demo@auditax.sample" Timestamp="2025-12-12T14:44:00.1234567Z" />
</AuditLog>

📚 Documentation

See the docs folder for detailed documentation:

Guides:


🧪 Samples

The samples folder contains working examples:

  • AuditaX.Sample.Dapper - Console app demonstrating Dapper integration
  • AuditaX.Sample.EntityFramework - Console app demonstrating EF Core integration

Database Setup

Use the DatabaseSetup tool to create sample databases:

# Create both SQL Server and PostgreSQL databases
dotnet run --project tools/AuditaX.Tools.DatabaseSetup -- all

# Create SQL Server only
dotnet run --project tools/AuditaX.Tools.DatabaseSetup -- sqlserver

# Create PostgreSQL only
dotnet run --project tools/AuditaX.Tools.DatabaseSetup -- postgresql

This creates:

  • SQL Server: AuditaX database with Products, ProductTags, Users, Roles, UserRoles tables
  • PostgreSQL: auditax database with the same tables (snake_case naming)

AuditLog tables are created automatically by AuditaX when AutoCreateTable = true.


📅 Versioning & .NET Support Policy

AuditaX follows a clear versioning strategy aligned with .NET's release cadence:

AuditaX .NET C# Status
2.x .NET 10 C# 14 Current

Future Support Policy

AuditaX will always support the current LTS version plus the next standard release. When a new LTS version is released, support for older versions will be discontinued:

AuditaX .NET C# Notes
2.x .NET 10 C# 14 LTS only
2.x .NET 10 + .NET 11 C# 14 / C# 15 LTS + Standard
3.x .NET 12 C# 16 New LTS (drops .NET 10/11)
4.x .NET 12 + .NET 13 C# 16 / C# 17 LTS + Standard

Why this policy?

  • Focused development: By limiting supported versions, we can dedicate more effort to quality, performance, and new features
  • Modern features: Each .NET version brings improvements that AuditaX can fully leverage
  • Clear upgrade path: Users know exactly when to plan their upgrades

Note: We recommend always using the latest LTS version of .NET for production applications.


⚙️ Requirements

  • .NET 10.0 or later
  • SQL Server 2016+ or PostgreSQL 12+
Product Compatible and additional computed target framework versions.
.NET 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 (4)

Showing the top 4 NuGet packages that depend on AuditaX:

Package Downloads
AuditaX.SqlServer

SQL Server database provider for AuditaX audit logging with optimized queries and native type support.

AuditaX.Dapper

Dapper ORM integration for AuditaX with IAuditUnitOfWork for manual audit control in lightweight data access scenarios.

AuditaX.EntityFramework

Entity Framework Core integration for AuditaX with automatic change tracking via SaveChanges interceptors.

AuditaX.PostgreSql

PostgreSQL database provider for AuditaX audit logging with optimized queries and native type support.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.4.1 618 6/10/2026
2.4.0 523 5/29/2026
2.3.1 592 5/25/2026
2.3.0 330 5/25/2026
2.2.1 345 5/25/2026
2.2.0 334 5/20/2026
2.1.0 374 5/1/2026
2.0.0 651 3/9/2026
1.2.4 332 3/9/2026
1.2.3 338 3/7/2026
1.2.2 342 3/3/2026
1.2.1 373 2/24/2026
1.2.0 384 2/24/2026
1.1.1 382 2/24/2026
1.1.0 405 2/21/2026
1.0.4 368 2/10/2026
1.0.3 611 12/17/2025

2.4.0: IAuditService now accepts an optional sourceReference on the user overloads of LogCreate/LogUpdate/LogDelete/LogRelated, and AuditService persists it (sets it on new AuditLog rows and refreshes it on existing ones). This lets the Dapper path populate SourceReference, matching the EF interceptor behavior. 2.3.1: Republish bump of 2.3.0 (version-only change). 2.3.0: SourceReference column widened to 512 chars; BREAKING: existing AuditLog tables must ALTER SourceReference to width >= 512.