3

I am having difficulty understanding the documentation for the Audit.NET Entity Framework Data Provider, to save Audit.NET WebAPI audit logs to my database.

This is how I have my Audit configuration set, just to test. I have a breakpoint inside the AuditEntityAction on entity.ChangeType = ev.EventType, but this never gets hit when I call an audited action on my controller.

Audit.Core.Configuration.Setup()
    .UseEntityFramework(x => 
        x.AuditTypeMapper(t => typeof(AuditLog))
            .AuditEntityAction<AuditLog>((ev, entry, entity) =>
            {
                entity.ChangeType = ev.EventType;
                entity.ObjectType = entry.EntityType.Name;
                entity.PrimaryKey = "test";
                entity.TableName = "test";
                entity.UserId = entry.CustomFields[UserIdField].ToString();
            })
            .IgnoreMatchedProperties()
        );

On my controller action, I have the decorator:

[AuditApi(EventTypeName = "Organisation:Create", IncludeRequestBody = true, IncludeResponseBody = true)]

Is this correct? I am not very clear on this, and I would appreciate some pointers.

JH-Sen-Ren
  • 259
  • 2
  • 12

2 Answers2

3

The Entity Framework Data Provider is part of the library Audit.EntityFramework and was designed to exclusively store the audits that are generated by an audited Entity Framework DbContext.

So it will not work for WebApi events of any other kind of event.

Here you can see how the audit event is discarded if it's not an AuditEventEntityFramework

So you should create your own Custom Data Provider or maybe use the SQL Data Provider.

thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • 1
    I would then argue that the documentation is misleading. The WebAPI Readme says `The audit events are stored using a Data Provider. You can use one of the available data providers or implement your own. Please refer to the data providers section on Audit.NET documentation.` When I then click through to the list of providers, the EntityFramework DP is listed. If the EntityFramework DP cannot be used except for EF Audit events, then perhaps a note to that effect would be very useful. – JH-Sen-Ren Nov 07 '19 at 08:56
  • Thanks. I've just added a note on the documentation. – thepirat000 Nov 07 '19 at 15:02
0

You can use Audit.NetWebApi package to get the WebApiAudit logs

public static void UseAudit(this IApplicationBuilder app, IHttpContextAccessor contextAccessor)
        {
            Audit.Core.Configuration.AddCustomAction(ActionType.OnScopeCreated, scope =>
            {
              
                    var entityTrack = scope.Event.GetEntityFrameworkEvent();
                    var requestTrack = scope.Event.GetWebApiAuditAction();
                    if (entityTrack!=null)
                    {
                        foreach (var item in entityTrack.Entries)
                        {
                            scope.Event.CustomFields[Table] = item.Table;
                            scope.Event.CustomFields[Action] = item.Action;
                        }
                    }
                    else if(requestTrack!=null)
                    {
                      
                        scope.Event.CustomFields[Action] = $"{requestTrack.ActionName}:{requestTrack.ActionName}";
                        scope.Event.CustomFields[RequestBody] = requestTrack.RequestBody.Value.ToString();
                        scope.Event.CustomFields[ResponseBody] = requestTrack.ResponseBody?.Value?.ToString()?? string.Empty;
                        scope.Event.CustomFields[Exception] = requestTrack.Exception?? string.Empty;
                    }
                
            });
        }

And then put this function in Startup.cs ConfigureApp

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IHttpContextAccessor contextAccessor)
            {
app.UseAudit(contextAccessor);
}

Constants used:

 private const string Table = "Table";
        private const string Action = "Action";           
        private const string RequestBody = "RequestBody";
        private const string ResponseBody = "ResponseBody";
        private const string Exception = "Exception";