简体   繁体   中英

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

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.

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());

Are you using a DI container? If you are or want to use a DI container, that could intercept all requests to the controllers. That way you don't change codes in hundreds of controllers, albeit simple change.

Here's Castle Windsor DI.

public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;

public WindsorControllerFactory(IKernel kernel)
{
    _kernel = kernel;
}

public override void ReleaseController(IController controller)
{
    _kernel.ReleaseComponent(controller);
}

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
    if (controllerType == null)
    {
        throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
    }

    return (IController)_kernel.Resolve(controllerType);
}
}

Have a look at the examples on this site if you intended to use it. I am sure there is a way to use it for both Web API and MVC controllers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM