1

I am using Audit.Net, (which is an excellent utility) to start auditing a system that was not designed with auditing in mind. Audit.Net is a life-saver in this case.

I assume someone must have had a similar scenario, and I'm asking this question because I have a feeling I'm not going down the best route.

There are different types of objects that need to be audited, but there is already a fixed table in the database (from another part of the system) into which the audited data must go.

Currently, I set the object that is passed via MVC / Web API Controller as the Target of the AuditEvent (using Audit.MVC version 14.2.1).

this.GetCurrentAuditScope().SetTargetGetter(() => leaveRequest);

I have extended AuditDataProvider and need to add each property of the Target object (in this case LeaveRequest) to a table. So in my SQLAuditDataProvider I get the new values of the LeaveRequest, and loop through its properties and write each non-null value to the database. The oldvalue with a LeaveRequest is not important. Here is an example:

if (auditEvent.Target.Type == "LeaveRequest")
{
    LeaveRequest leaveReq = JsonConvert.DeserializeObject<LeaveRequest>(auditEvent.Target.SerializedNew.ToString());                       

    foreach (var property in leaveReq.GetType().GetProperties().Where(property => !property.GetGetMethod().GetParameters().Any()))
    {
        if (property.GetValue(leaveReq) != null)
        {
            var sqlResult = context.sp_ESS_InsertResourceAudit(leaveReq.ResourceTag, dbObjectName, username, property.Name, oldValue,property.GetValue(leaveReq).ToString(), auditEvent.StartDate, auditControlTableID.ToString(),auditEvent.Environment.CallingMethodName);
        }
    }

}

But, of course, this only works with LeaveRequest. So along comes any other object that is set as the Target of AuditEvent, and I have a problem. How do I make the above code generic so that it can handle any object (and even an int?)

I also thought of using the Action Parameters, but then each object needs to have its ToString fleshed out (which could be lots of manual work plus string manipulation to get hold of the properties), and it just doesn't feel nice and tidy.

So I don't know whether this question is more a plain generics one, than an Audit.Net one, but I think the Audit.Net context is important, and perhaps setting the object in each case as the Target is not a good idea. I would be interested to know how other people use Audit.Net to audit different types of objects that need the same way of output.

Aarif
  • 1,595
  • 3
  • 17
  • 29
Igavshne
  • 699
  • 7
  • 33

1 Answers1

0

If you don't care about the "old" value, do not use the Target object, use a Custom Field instead, so you avoid the unnecessary serialization/deserialization.

this.GetCurrentAuditScope().SetCustomField("LeaveRequest", leaveRequest);

So on your data provider:

if (auditEvent.CustomFields.ContainsKey("LeaveRequest"))
{
    var leaveReq = auditEvent.CustomFields["LeaveRequest"] as LeaveRequest;
    InsertLeaveRequest(leaveReq);
}
if (auditEvent.CustomFields.ContainsKey("AnotherField"))
{
    var another = auditEvent.CustomFields["AnotherField"] as AnotherType;
    InsertAnotherType(another);
}
...

For only three types of objects you probably don't need to have a generic solution that will imply more testing, etc...

thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • Thank you for your speedy reply. I thought I would need the oldValue in some cases, but I checked with another programmer that worked on the system, -and it seems not. So okay, I could use the CustomField instead of the Target. However, there won't only be three types of objects, probably more than ten but hopefully not more than thirty. So I am thinking of a more generic solution. I am also wondering what would be easiest for someone taking my place in the future. – Igavshne May 09 '19 at 14:09