Rudazzle
Rudazzle

Reputation: 355

Audit.NET - Entity Framework - Log Based on Business Action using AuditScope

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

I'd like to be able to audit certain business actions that affect multiple entities while not auditing every modification to the entity. For example, if a user is deleted then I want to log every table that will be modified. In this environment, not all of the entities are set up with relationships so I can't just include the object graph. I don't want to log every modification to the Emails entity, just log this data when an employee is being deleted.

I thought I could use the AuditScope.Create() functionality to be able to handle this scenario but I'm not having any luck.

Currently, I configure Audit.NET on startup with the following code.

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

In my controller action, I'm trying to log the change via the AuditScope object. I want to be able to log modifications for any objects which are saved within the using.

I've tried this a couple of different ways but have not had any luck. Employee is just a class I created to contain my various entities and is not an actual entity mapped to the database.

            var employee = new Employee();
            employee.Users = _db.Users.Where(x => x.EmpId == empid).ToList();
            employee.Emails = _db.Emails.Where(x => x.EmpId == empid).ToList();
            employee.Phones = _db.Phones.Where(x => x.EmpId == empid).ToList();

            using (AuditScope.Create("DeleteEmployee", () => employee))
            {
                _db.Users.RemoveRange(employee.Users);
                _db.Emails.RemoveRange(employee.Emails);
                _db.Phones.RemoveRange(employee.Phones);
                
                var EmployeeLog = new EmployeeLog
                {
                    ActionType = "Delete",
                    DeletedBy = ScopeUser.ID,
                    DeletedUser = employee.Users[0].UserName,
                    DeletedOn = DateTime.Now
                };

                _db.EmployeeLogs.Add(EmployeeLog);
                _db.SaveChanges();
            }    

Here's my Employee Class definition:

[AuditInclude]
public class Employee
{
    public List<tbl_User> Users { get; set; }
    public List<tbl_Email> Emails { get; set; }
    public List<tbl_Phone> Phones { get; set; }
}

I also tried the following implementation without using the Employee class but nothing was logged for it either.

var user = _db.Users.Where(x => x.EmpId == empid).ToList();
var emails = _db.Emails.Where(x => x.EmpId == empid).ToList();
var phones = _db.Phones.Where(x => x.EmpId == empid).ToList();

using (AuditScope.Create("DeleteEmployee", () => new { User = user, Emails = emails, Phones = phones }))
{
        _db.Users.RemoveRange(user);
        _db.Emails.RemoveRange(emails);
        _db.Phones.RemoveRange(phones);
        var EmployeeLog = new EmployeeLog
        {
             ActionType = "Delete",
             DeletedBy = ScopeUser.ID,
             DeletedUser = user[0].UserName,
             DeletedOn = DateTime.Now
         };

         _db.EmployeeLogs.Add(EmployeeLog);
         _db.SaveChanges();
}                

Other entities that have the [AuditInclude] attribute are logging as expected. Either my configuration is incorrect, you can't mix AuditScope and Audit.EntityFramework this way or AuditScope is not intended to be used to track multiple entities. Any direction that can be provided would be greatly appreciated.

Upvotes: 1

Views: 2949

Answers (1)

thepirat000
thepirat000

Reputation: 13114

Note the EntityFramework Data Provider (.UseEntityFramework()) will only log the audit events generated by the Audit.EntityFramework library. It will discard any other audit event type.

So you cannot make the Entity Framework Data Provider to log an arbitrary event created via AuditScope.Create() (unless you manually create an Audit.EntityFramework.AuditEventEntityFramework, but that makes little sense)

Looks like you are logging everything to the same Audit Log table, so you can probably use the SQL Data Provider that will log any type of audit event.

If you need to use multiple data providers (EF logging using Audit.EF and its data provider, and also some other manual logging) check the following:

Upvotes: 1

Related Questions