Skip to content

Samples

RzR edited this page Apr 20, 2026 · 1 revision

Samples

The repository includes several sample projects covering different .NET versions, storage backends, and hosting models. They're all under the samples/ directory and demonstrate real-world registration patterns.


Web API samples

All web API samples follow the same domain model: a blog with Post and Comment entities. They include CRUD controllers plus an AuditController that queries the audit store so you can see what got logged.

EF Core + PostgreSQL

Project .NET Version Pattern
WebApiEfPostgreSqlNet5 .NET 5.0 Startup.cs (classic)
WebApiEfPostgreSqlNet6 .NET 6.0 Minimal API
WebApiEfPostgreSqlNet7 .NET 7.0 Minimal API
WebApiEfPostgreSqlNet8 .NET 8.0 Minimal API
WebApiEfPostgreSqlNet9 .NET 9.0 Minimal API

The .NET 5 sample uses Startup.ConfigureServices / Startup.Configure. The rest use the minimal hosting model in Program.cs.

Each sample includes:

  • AuditSourceResolver - returns a custom application identifier
  • BlogDbContext with Post and Comment entities marked IAuditable
  • GDPR policy configuration (in the .NET 6+ variants)
  • Controllers for Posts, Comments, and Audit

EF Core + SQL Server

Project .NET Version Pattern
WebApiEfSqlServerNet5 .NET 5.0 Startup.cs (classic)
WebApiEfSqlServerNet6 .NET 6.0 Minimal API

Same blog domain. The .NET 6 variant has a more complete setup with full CRUD controllers and an AuditController for browsing audit records.

EF Core + MongoDB

Project .NET Version
WebApiEfMongoDbNet8 .NET 8.0

This one shows the MongoDB-specific setup: UseMongoDb(connStr, dbName), AddAuditTrailMongoDb(), AddAuditReadInterceptor(sp), and UseAuditReadFlush(). No migration step needed.


Worker service sample

Project Description
SampleWorkerService Background service with no HTTP pipeline

Demonstrates:

  • Custom WorkerSourceResolver returning "OrderProcessingService"
  • Using IAuditScopeContext.SetUser() to manually set audit user identity
  • Building AuditTransaction objects by hand
  • Calling AuditPipeline.ProcessAsync() directly

This is the reference implementation for non-web scenarios.


Running a sample

  1. Make sure the target database is accessible (update the connection string in appsettings.json)
  2. cd samples/ef/WebApiEfSqlServerNet6 (or whichever sample)
  3. dotnet run
  4. Create a post: POST /api/posts with a JSON body
  5. Check audit records: GET /api/audit

For the MongoDB sample, you need a MongoDB instance running on localhost:27017 (or update the connection string).

For the worker sample, it runs as a background service and logs audit events periodically. Just dotnet run and watch the console output (or check the audit store).


FAQ and Troubleshooting

Common questions

Do I need all the packages?

No. RzR.DataVigil.Core is the only mandatory one. Add EFCore if you want automatic interception, AspNetCore if you're in a web app, and one storage package. See the Package Reference Summary.

Can I audit multiple DbContexts?

Yes. Call options.EfCore.Intercept<T>() for each context, and make sure each context registration includes opts.AddAuditInterceptors(sp).

What .NET versions are supported?

The library targets .NET Standard 2.1, which means .NET Core 3.0+, .NET 5+, .NET 6+, etc. The MongoDB storage package targets net8.0 specifically because the MongoDB EF Core provider requires it. The sample projects demonstrate usage across .NET 5 through .NET 9.

Can I use a different database for the audit store vs. my app?

Yes, and it's recommended. The AuditDb connection string points to the audit database, while your app's DbContext uses its own connection string. They're completely independent.

What happens if the audit store fails?

The main SaveChanges still goes through. Audit failures are handled within the pipeline and don't block or roll back the application's database operations.

Does read auditing affect performance?

It adds overhead because the interceptor fires on every SELECT. For high-throughput read scenarios, test the impact before enabling it in production. Consider enabling it only on specific contexts or using manual read logging (AuditReadService) for targeted auditing.


Troubleshooting

Audit records aren't being created

Check these in order:

  1. Is your entity marked with IAuditable?
  2. Did you call options.EfCore.Intercept<YourDbContext>()?
  3. Did you call opts.AddAuditInterceptors(sp) in your AddDbContext registration?
  4. Did you call AddAuditTrailEfCore()?
  5. Did you register a storage provider (AddAuditTrailSqlServer(), etc.)?
  6. For SQL-based stores: did you run the migration (MigrateAuditSqlServerDb())?

"No service for type 'IAuditStore'" exception

You forgot to register a storage provider. Add one of:

  • services.AddAuditTrailSqlServer()
  • services.AddAuditTrailPostgreSqlServer()
  • services.AddAuditTrailMongoDb()
  • services.AddAuditTrailFileStorage()

UserId is null in audit records

In ASP.NET Core: make sure AddAuditTrailAspNetCore() is called and the request has an authenticated user. Check that your auth middleware runs before the controller.

In a worker/console: you need to call IAuditScopeContext.SetUser() explicitly before pushing transactions.

GDPR policies aren't being applied

Verify that:

  1. The entity type in ForEntity<T>() matches the entity being audited
  2. The property expression points to the right field
  3. The entity implements IAuditable (GDPR policies only apply to auditable entities)

Read entries show up but are empty

Make sure you called IncludeReadProperties() on the EF Core options. Without it, only entity names and IDs are captured - no property details.

Infinite recursion / stack overflow on SaveChanges

This shouldn't happen if you're using the library correctly. The interceptor has a built-in guard that skips any DbContext inheriting from AuditDbContextBase. If you're seeing this, make sure your audit DbContext extends AuditDbContextBase (the storage packages handle this automatically).

File storage: "file is in use" errors

FileAuditStore uses lock for thread safety, but it won't protect against multiple processes writing to the same directory. If you have multiple app instances, use a database-backed store instead of file storage.

Clone this wiki locally