What is the clean way to Implement Audit Trail in Asp.net MVC and Web API

Joe.wang picture Joe.wang · Sep 25, 2015 · Viewed 10.4k times · Source

I am trying to look for a more clean way to add audit trail function to an exist asp.net MVC and Web Api project which contains hundreds of Controller and ApiController.

The Audit trail log would look like below. Basically I just want to log In what time who did what in this function.

UserID

ActionTime

Controller 

Action

Anything I missed ? If there is . Please correct me. Thanks.

Currently I found there are some ways to make it .

  1. Implement an ActionFilterAttribute and write my own log function in the OnActionExecuting, and then decorate all the actions with this attribute.

  2. Implement a base Controller like BaseController for all the exist controller. And write log in the OnActionExecuting. Then change all the controller to inherit from BaseController. (If it is wrong . Please correct me . Thanks.)

  3. For the ApiController. Implement a DelegatingHandler to make it.

For 1 and 2. I need change to all the exist code to make it. like change base class or decorate with new attribute. Considering in my case, This will be a hard work. Because thousands of class or methods need to be changed . I thinks it is kind of verbose. So I wondered if there is some clean way like 3 for ApiController to make it. Thanks.

Answer

Ronald Rogers picture Ronald Rogers · Sep 25, 2015

I find that using global action filters is the best way to handle cross-cutting/aspect-oriented concerns such as this.

Note that this code is not tested.

public class AuditFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var userName = HttpContext.Current.User.Identity.Name;
        var time = DateTime.Now.ToString(CultureInfo.InvariantCulture);
        var controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
        var actionName = actionContext.ActionDescriptor.ActionName

        Logger.Log(string.Format("user: {0}, date: {1}, controller {2}, action {3}", userName, time, controllerName, actionName));
    }
}

And somewhere in your application startup pipeline, register the filter globally:

GlobalConfiguration.Configuration.Filters.Add(new AuditFilter());