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.