如何使用ActionFilterAttribute记录运行时间?

时间:2014-03-20 14:25:25

标签: c# asp.net-mvc logging asp.net-web-api action-filter

我创建了一个动作过滤器,用于测量Web API v2中每个动作的运行时间。

public class RunningTimeAttribute : ActionFilterAttribute
    {
        private readonly ILogFactory _logFactory;
        private readonly ITimerFactory _timerFactory;
        private ITimer _timer;
        private ILogger _logger;

        public RunningTimeAttribute(ILogFactory logFactory, ITimerFactory timerFactory) {
            if(logFactory == null)
                throw new ArgumentNullException("logFactory");
            if(timerFactory == null)
                throw new ArgumentNullException("timerFactory");

            _logFactory = logFactory;
            _timerFactory = timerFactory;
        }

        public override void OnActionExecuting(HttpActionContext actionContext) {
            base.OnActionExecuting(actionContext);
            OnBeforeAction(actionContext);
        }

        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
            OnAfterAction(actionExecutedContext);
            base.OnActionExecuted(actionExecutedContext);
        }

        private void OnBeforeAction(HttpActionContext actionContext) {
            var controllerName = actionContext.ControllerContext.Controller.GetType().FullName;
            var actionName = actionContext.ActionDescriptor.ActionName;

            _logger = _logFactory.Create(controllerName);
            _logger.Trace("Action \"{0}\" begins execution", actionName);

            _timer = _timerFactory.Create();
            _timer.Start();
        }

        private void OnAfterAction(HttpActionExecutedContext actionExecutedContext) {
            var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;

            _timer.Stop();
            _logger.Trace("Time elapsed for action \"{0}\": {1} msec", actionName, _timer.ElapsedMilliseconds);
        }

}

但是,操作过滤器充当单例,因此当OnActionExecuted运行时,我无法确定_logger_timer是否与为相同的操作创建的OnActionExecuting { {1}}

EG。

  1. 操作Foo1开始执行。 _logger = "logger1"_timer = "timer1"
  2. 动作Foo2开始执行。 _logger = "logger2"_timer = "timer2"(他们被覆盖)
  3. 动作Foo1结束执行。它会停止计时器并记录经过的时间,这是无意义的(end1-start2)。
  4. 问题:我可以在OnActionExecuted中了解OnActionExecuting对应的方式吗?如果有一些唯一的动作标识符,我可以将它用作Dictionary的一个键来存储任何与动作相关的对象,如记录器和定时器。有没有?还是其他一些解决方案?

2 个答案:

答案 0 :(得分:6)

就Web API而言,System.Web.HttpContext.Current并不总能得到保证。这取决于您是否使用Web API Self托管。这就是当覆盖System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuting时你没有在HttpActionContext参数上获得httpcontext属性的主要原因(在AspNet MVC中)。

执行相同操作的最佳方式是actionContext.Request.Properties字典。

同时查看此答案here

答案 1 :(得分:1)

System.Web.HttpContext.Current.Items是每请求缓存存储 您可以安全地在OnBeforeAction方法的Items中添加计时器对象,并从OnAfterAction方法中的Items中检索此计时器对象