Audit.NET - Entity Framework - Filter audit events based on Action

1k Views Asked by At

I'm in the process of implementing Auditing with Audit.NET and Entity Framework with an MVC application running .NET 4.6.1.

I have a requirement to be able to restrict auditing based on the database operation being performed. I've reviewed the documentation and see that I can control this via the AuditEntityAction by writing custom code.

What I'm looking for is the ability to attribute my data models to indicate which operations should be audited. I can create this logic if it doesn't exist but thought I'd check with the dev community first. Below is an example of what I'm looking for.

[AuditInclude("DELETE")]

or

[AuditInclude("DELETE", "UPDATE")]
2

There are 2 best solutions below

0
On BEST ANSWER

You can make the function AuditEntityAction to return a boolean to indicate whether to include (true) or ignore (false) the entity on the output log.

For example:

Audit.Core.Configuration.Setup()
    .UseEntityFramework(ef => ef
        .AuditTypeMapper(t => typeof(AuditLog))
        .AuditEntityAction<AuditLog>((ev, entry, entity) =>
        {
            // your code...

            return entry.EntityType == typeof(Employee) && entry.Action == "Delete";
        })
        .IgnoreMatchedProperties(true));
0
On

I accepted "thepirate000" answer as it provided me with the solution, but ultimately I did the implementation slightly different. I created a class called AuditIncludeActionAttribute which can be added to any models in addition to the [AuditInclude] attribute. I also created an enumeration called AuditActionOptions for readability.

/// <summary>
/// Used with OptIn AnnotationMode to specify actions for auditing
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class AuditIncludeActionAttribute : Attribute
{
    public List<AuditActionOptions> AuditActions;

    public AuditIncludeActionAttribute(AuditActionOptions auditActionOption)
    {
        this.AuditActions = new List<AuditActionOptions>();
        this.AuditActions.Add(auditActionOption);
    }

    public AuditIncludeActionAttribute(AuditActionOptions auditActionOption1, AuditActionOptions auditActionOption2)
    {
        this.AuditActions = new List<AuditActionOptions>();
        this.AuditActions.Add(auditActionOption1);
        this.AuditActions.Add(auditActionOption2);
    }
}

public enum AuditActionOptions
{
    Insert = 1,
    Update = 2,
    Delete = 3        
} 

I then added the following code to the setup to determine if the data should be audited. The performance was acceptable in my use case.

    Audit.Core.Configuration.Setup()
        .UseEntityFramework(ef => ef
            .AuditTypeMapper(t => typeof(AuditLog))
            .AuditEntityAction<AuditLog>((ev, entry, entity) =>
            {
                entity.AuditData = entry.ToJson();
                entity.AuditDate = DateTime.Now;
                entity.AuditUserId = SessionHelper.UserKey;
                entity.TablePk = entry.PrimaryKey.First().Value.ToString();
                entity.Duration = ev.Duration;
                entity.Action = entry.Action;
                entity.SchemaName = entry.Schema;
                entity.TableName = entry.Table;
                var entityFrameworkEvent = ev.GetEntityFrameworkEvent();
                entity.TransactionId = entityFrameworkEvent.TransactionId;

                AuditIncludeActionAttribute actionAttribute = (AuditIncludeActionAttribute)Attribute.GetCustomAttribute(entry.EntityType, typeof(AuditIncludeActionAttribute));

                // If there is no AuditIncludeActionAttribute then the entity only has the AuditInclude attribute and should log all actions
                if (actionAttribute == null)
                {
                    return true;
                }
                else if (entry.Action.ToUpper() == "DELETE" && actionAttribute.AuditActions.Contains(AuditActionOptions.Delete))
                {
                    return true;
                }
                else if (entry.Action.ToUpper() == "INSERT" && actionAttribute.AuditActions.Contains(AuditActionOptions.Insert))
                {
                    return true;
                }
                else if (entry.Action.ToUpper() == "UPDATE" && actionAttribute.AuditActions.Contains(AuditActionOptions.Update))
                {
                    return true;
                }
                else
                {
                    return false;
                }

            })
        .IgnoreMatchedProperties(true));