VOOZH about

URL: https://www.nuget.org/packages/Pandatech.EFCore.Audit/

⇱ NuGet Gallery | Pandatech.EFCore.Audit 3.0.2




👁 Image
Pandatech.EFCore.Audit 3.0.2

dotnet add package Pandatech.EFCore.Audit --version 3.0.2
 
 
NuGet\Install-Package Pandatech.EFCore.Audit -Version 3.0.2
 
 
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="Pandatech.EFCore.Audit" Version="3.0.2" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pandatech.EFCore.Audit" Version="3.0.2" />
 
Directory.Packages.props
<PackageReference Include="Pandatech.EFCore.Audit" />
 
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 Pandatech.EFCore.Audit --version 3.0.2
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Pandatech.EFCore.Audit, 3.0.2"
 
 
#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 Pandatech.EFCore.Audit@3.0.2
 
 
#: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=Pandatech.EFCore.Audit&version=3.0.2
 
Install as a Cake Addin
#tool nuget:?package=Pandatech.EFCore.Audit&version=3.0.2
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Pandatech.EFCore.Audit

Automatic audit trail tracking for Entity Framework Core 8+ with configurable property transformations, composite key support, and manual bulk auditing.

Installation

dotnet add package Pandatech.EFCore.Audit

Quick Start

1. Configure Entities for Auditing

public class Blog
{
 public int Id { get; set; }
 public string Title { get; set; }
 public DateTime CreatedAt { get; set; }
 public byte[] EncryptedKey { get; set; }
}

public class BlogAuditConfiguration : AuditTrailConfigurator<Blog>
{
 public BlogAuditConfiguration()
 {
 SetReadPermission(Permission.UserPermission);
 WriteAuditTrailOnEvents(AuditActionType.Create, AuditActionType.Update, AuditActionType.Delete);
 RuleFor(x => x.EncryptedKey).Transform(Convert.ToBase64String);
 }
}

2. Create Audit Consumer

public class AuditTrailConsumer : IAuditTrailConsumer
{
 public Task ConsumeAuditTrailAsync(AuditTrailEventData eventData, CancellationToken ct = default)
 {
 // Log to database, send to message queue, etc.
 Console.WriteLine(JsonSerializer.Serialize(eventData));
 return Task.CompletedTask;
 }
}

3. Register Services

var builder = WebApplication.CreateBuilder(args);

// Register audit trail BEFORE DbContext
builder.AddAuditTrail<AuditTrailConsumer>(typeof(Program).Assembly);

// Register DbContext with audit interceptors
builder.Services.AddDbContext<AppDbContext>((sp, options) =>
{
 options.UseNpgsql(connectionString)
 .AddAuditTrailInterceptors(sp);
});

Configuration API

Entity Configuration

public class PostAuditConfiguration : AuditTrailConfigurator<Post>
{
 public PostAuditConfiguration()
 {
 // Set service name for this entity
 SetServiceName("BlogService");
 
 // Track only specific events (default: all events)
 WriteAuditTrailOnEvents(AuditActionType.Create, AuditActionType.Update);
 
 // Set read permission for row-level security
 SetReadPermission(Permission.AdminOnly);
 
 // Property transformations
 RuleFor(x => x.Content).Ignore(); // Don't track
 RuleFor(x => x.Title).Rename("PostTitle"); // Rename in audit
 RuleFor(x => x.Price).Transform(x => Math.Round(x, 2)); // Transform value
 }
}

Property Configuration Methods

Method Description Example
Ignore() Skip tracking this property RuleFor(x => x.Password).Ignore()
Rename(string) Change property name in audit trail RuleFor(x => x.Email).Rename("UserEmail")
Transform<TOutput>(Func) Transform value before auditing RuleFor(x => x.Data).Transform(Encrypt)

Entity Configuration Methods

Method Description
SetServiceName(string) Identify the originating service
SetReadPermission(object) Set permission level for row-level security
WriteAuditTrailOnEvents(params AuditActionType[]) Track only specific events (Create, Update, Delete)

Audit Event Data

public record AuditTrailEventData(List<AuditTrailEventEntity> Entities);

public record AuditTrailEventEntity(
 EntityEntry? EntityEntry, // EF Core entity entry (null for manual audits)
 string? ServiceName, // Service identifier
 AuditActionType ActionType, // Create, Update, or Delete
 string Name, // Entity type name
 object? ReadPermission, // Permission level
 string PrimaryKeyValue, // Composite keys joined with '_'
 Dictionary<string, object?> TrackedProperty
);

Example audit event:

{
 "entities": [{
 "serviceName": "BlogService",
 "actionType": "Update",
 "name": "Blog",
 "readPermission": 1,
 "primaryKeyValue": "123",
 "trackedProperty": {
 "title": "New Title",
 "encryptedKey": "AQID"
 }
 }]
}

Manual Bulk Auditing

For operations outside EF Core's change tracker (raw SQL, ExecuteUpdate, AsNoTracking, external APIs):

public class MyService
{
 private readonly IAuditTrailPublisher _publisher;
 
 public async Task BulkCreatePosts()
 {
 // Your untracked operations...
 await db.Database.ExecuteSqlRawAsync("INSERT INTO Posts ...");
 
 // Manually create audit entries
 var auditEntries = new List<ManualAuditEntry>
 {
 new(
 EntityType: typeof(Post),
 Action: AuditActionType.Create,
 ChangedItems: new List<AuditEntryDetail>
 {
 new(
 PrimaryKeyIds: ["1"],
 ChangedProperties: new Dictionary<string, object?>
 {
 ["Title"] = "My Post",
 ["Content"] = "Post content",
 ["BlogId"] = 42
 }
 ),
 new(
 PrimaryKeyIds: ["2"],
 ChangedProperties: new Dictionary<string, object?>
 {
 ["Title"] = "Another Post",
 ["Content"] = "More content",
 ["BlogId"] = 42
 }
 )
 }
 )
 };
 
 await _publisher.BulkAuditAsync(auditEntries);
 }
}

Features

Automatic change tracking - Hooks into EF Core's change tracker
Composite key support - Concatenates composite keys with _ delimiter
Property transformations - Ignore, rename, or transform tracked properties
Transaction support - Publishes audit events after transaction commit
Manual bulk auditing - Track untracked operations like raw SQL
Configurable permissions - Row-level security support via SetReadPermission
Service identification - Track which service made the change
Partial tracking - For updates, only changed properties are tracked

Limitations

⚠️ Not atomic - Event-based architecture means audit data could be lost in edge cases
⚠️ No untracked operations - AsNoTracking, ExecuteUpdate, ExecuteDelete are not automatically audited (use manual bulk audit)

Advanced Usage

Composite Keys

public class OrderItem
{
 public int OrderId { get; set; }
 public int ProductId { get; set; }
 // ...
}

Audit event: primaryKeyValue: "123_456" (OrderId_ProductId)

Custom Transformations

public class UserAuditConfiguration : AuditTrailConfigurator<User>
{
 public UserAuditConfiguration()
 {
 RuleFor(x => x.Email).Transform(x => MaskEmail(x));
 RuleFor(x => x.Salary).Transform(x => x * 0.01m); // Store in cents
 RuleFor(x => x.CreatedAt).Transform(x => x.ToString("o")); // ISO 8601
 }
 
 private static string MaskEmail(string email)
 {
 var parts = email.Split('@');
 return parts.Length == 2 
 ? $"{parts[0][0]}***@{parts[1]}" 
 : email;
 }
}

Selective Event Tracking

public class SensitiveDataConfig : AuditTrailConfigurator<SensitiveData>
{
 public SensitiveDataConfig()
 {
 // Only track deletions, not creates or updates
 WriteAuditTrailOnEvents(AuditActionType.Delete);
 }
}

Event Consumer Examples

Database Consumer

public class DatabaseAuditConsumer : IAuditTrailConsumer
{
 private readonly AuditDbContext _auditDb;
 
 public async Task ConsumeAuditTrailAsync(AuditTrailEventData eventData, CancellationToken ct)
 {
 var auditRecords = eventData.Entities.Select(e => new AuditRecord
 {
 EntityName = e.Name,
 Action = e.ActionType.ToString(),
 PrimaryKey = e.PrimaryKeyValue,
 Changes = JsonSerializer.Serialize(e.TrackedProperty),
 Timestamp = DateTime.UtcNow,
 ServiceName = e.ServiceName,
 Permission = e.ReadPermission?.ToString()
 });
 
 _auditDb.AuditRecords.AddRange(auditRecords);
 await _auditDb.SaveChangesAsync(ct);
 }
}

Message Queue Consumer

public class RabbitMqAuditConsumer : IAuditTrailConsumer
{
 private readonly IMessagePublisher _publisher;
 
 public async Task ConsumeAuditTrailAsync(AuditTrailEventData eventData, CancellationToken ct)
 {
 var message = new AuditMessage
 {
 Timestamp = DateTime.UtcNow,
 Events = eventData.Entities
 };
 
 await _publisher.PublishAsync("audit-trail", message, ct);
 }
}

Registration Order

⚠️ Important: AddAuditTrail must be called before AddDbContext:

// ✅ Correct order
builder.AddAuditTrail<AuditConsumer>(typeof(Program).Assembly);
builder.Services.AddDbContext<AppDbContext>(...);

// ❌ Wrong order - will not work
builder.Services.AddDbContext<AppDbContext>(...);
builder.AddAuditTrail<AuditConsumer>(typeof(Program).Assembly);

If you must register DbContext first, manually add HttpContextAccessor:

builder.Services.AddHttpContextAccessor();
builder.Services.AddDbContext<AppDbContext>(...);
builder.AddAuditTrail<AuditConsumer>(typeof(Program).Assembly);

Supported Databases

  • PostgreSQL
  • SQL Server
  • MySQL
  • SQLite
  • Any database supported by EF Core Relational

License

MIT

Product Versions Compatible and additional computed target framework versions.
.NET net8.0 net8.0 is compatible.  net8.0-android net8.0-android was computed.  net8.0-browser net8.0-browser was computed.  net8.0-ios net8.0-ios was computed.  net8.0-maccatalyst net8.0-maccatalyst was computed.  net8.0-macos net8.0-macos was computed.  net8.0-tvos net8.0-tvos was computed.  net8.0-windows net8.0-windows was computed.  net9.0 net9.0 is compatible.  net9.0-android net9.0-android was computed.  net9.0-browser net9.0-browser was computed.  net9.0-ios net9.0-ios was computed.  net9.0-maccatalyst net9.0-maccatalyst was computed.  net9.0-macos net9.0-macos was computed.  net9.0-tvos net9.0-tvos was computed.  net9.0-windows net9.0-windows was computed.  net10.0 net10.0 is compatible.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows 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 (1)

Showing the top 1 NuGet packages that depend on Pandatech.EFCore.Audit:

Package Downloads
Pandatech.SharedKernel.Postgres

PostgreSQL integration helpers for ASP.NET Core 10: DbContext registration with or without pooling and audit trail, migrations, health checks, snake_case naming, query locks, exception mapping, and bulk extensions.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.2 123 6/3/2026
3.0.1 123 6/1/2026
3.0.0 320 2/28/2026
2.0.1 149 1/26/2026
2.0.0 164 12/28/2025
1.2.5 470 8/7/2025
1.2.4 317 6/1/2025
1.2.3 385 3/12/2025
1.2.2 262 2/17/2025
1.2.1 273 12/26/2024
1.2.0 232 12/26/2024
1.1.4 240 12/5/2024
1.1.3 240 12/3/2024
1.1.2 217 12/3/2024
1.1.1 219 12/3/2024
1.1.0 224 12/3/2024
1.0.0 208 12/2/2024

Multi-target net8.0/9.0/10.0, Update Audit Tracking Service Logic