EF Core: How to implement basic Auditing on your Entities
Tags: csharp, dotnet, dotnetcore, efcore
Published: 2020-06-01 08:00:48

---
title: EF Core: How to implement basic Auditing on your Entities
published: true
description: In this post I'll demonstrate how to implement basing auditing on your entity framework core database entities
tags: csharp, dotnet, dotnetcore, efcore
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/vbnoy57bi03jf5fgml5y.jpg
---

# EF Core Audit properties

A common requirement but also a good practice is to add some some auditing properties in all the entities you save in the database.

The most common properties to use are:
1. `CreateBy` (The user who created the initial entry)
2. `ModifiedBy` (The user who modified the entry last)
3. `CreatedAt` (The datetime of creation of initial Entry)
3. `ModifiedAt` (The datetime the entry was last modified)

## Let's start implementing this functionality

First we are going to create a new base class named AuditableEntity that every other entity will inherit from when we need to add the audit functionality.

```csharp
public class AuditableEntity
{
    public string CreatedBy { get; set; }
    public string ModifiedBy { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime ModifiedAt { get; set; }
}
```

For example if we have a Transaction entity and we want to add audit functionality we would inherit from our `AuditableEntity` like that:

```csharp
public class Transaction : AuditableEntity
{
    public long TransactionId { get; set; }
    public string FromIban { get; set; }
    public string ToIban { get; set; }
    public decimal Amount { get; set; }
}
```

Now our Transaction class will have all the audit properties **but** we don't want to manually set these properties each time, we need to somehow move this responsibility to a single place.
The best place for this is the `SaveChanges` and `SaveChangesAsync`, so we'll have to override them in our `DbContext` class.

Here is how you would do it for the `SaveChangesAsync`:

```csharp
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
    // Get all the entities that inherit from AuditableEntity
    // and have a state of Added or Modified
    var entries = ChangeTracker
        .Entries()
        .Where(e => e.Entity is AuditableEntity && (
                e.State == EntityState.Added
                || e.State == EntityState.Modified));
    
    // For each entity we will set the Audit properties
    foreach (var entityEntry in entries)
    {
        // If the entity state is Added let's set
        // the CreatedAt and CreatedBy properties
        if (entityEntry.State == EntityState.Added)
        {
            ((AuditableEntity)entityEntry.Entity).CreatedAt = DateTime.UtcNow;
            ((AuditableEntity)entityEntry.Entity).CreatedBy = this.httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "MyApp";
        }
        else
        {
            // If the state is Modified then we don't want
            // to modify the CreatedAt and CreatedBy properties
            // so we set their state as IsModified to false
            Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedAt).IsModified = false;
            Entry((AuditableEntity)entityEntry.Entity).Property(p => p.CreatedBy).IsModified = false;
        }

        // In any case we always want to set the properties
        // ModifiedAt and ModifiedBy
        ((AuditableEntity)entityEntry.Entity).ModifiedAt = DateTime.UtcNow;
        ((AuditableEntity)entityEntry.Entity).ModifiedBy = this.httpContextAccessor?.HttpContext?.User?.Identity?.Name ?? "MyApp";
    }

    // After we set all the needed properties
    // we call the base implementation of SaveChangesAsync
    // to actually save our entities in the database
    return await base.SaveChangesAsync(cancellationToken);
}
```

In this example I am using the `HttpContextAccessor` to get the current user in my .NET Core Web API.
To have `HttpContextAccessor` available you just inject it into your `DbContext` class.
In order for `HttpContextAccessor` to be available for injection you need to add it in your `Startup.cs` file inside `ConfigureServices` method like that:

```csharp
services.AddHttpContextAccessor();
```

And that's it! That's how simple it is to implement basic auditing for your entities using Entity Framework Core.

# MS SQL Server Audit Features

Please keep in mind that for a full featured auditing you can use SQL Server's [Track Data Changes](https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/track-data-changes-sql-server?view=sql-server-ver15#Capture), it is available in two flavors:

### Change Data Capture

>Change data capture provides historical change information for a user table by capturing both the fact that DML changes were made and the actual data that was changed. Changes are captured by using an asynchronous process that reads the transaction log and has a low impact on the system.

### Change Tracking

>Change tracking captures the fact that rows in a table were changed, but does not capture the data that was changed. This enables applications to determine the rows that have changed with the latest row data being obtained directly from the user tables. Therefore, change tracking is more limited in the historical questions it can answer compared to change data capture. However, for those applications that do not require the historical information, there is far less storage overhead because of the changed data not being captured. A synchronous tracking mechanism is used to track the changes. This has been designed to have minimal overhead to the DML operations.

You can read more about it on the official docs [here](https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/track-data-changes-sql-server?view=sql-server-ver15#Capture)

You can find the full code on my [GitHub](https://github.com/Rickinio/EFCoreAuditExample)

This post was written with love ❤️