Как использовать ActionFilterAttribute для записи времени выполнения?

Я создал фильтр действий для измерения времени выполнения каждого действия в 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. Действие Foo1 начинает выполнение. _logger = "logger1", _timer = "timer1",
  2. Действие Foo2 начинает выполнение. _logger = "logger2", _timer = "timer2" (они переопределяются)
  3. Действие Foo1 завершает выполнение. Он останавливает таймер и записывает прошедшее время, что является бессмысленным (end1-start2).

Вопрос: есть ли способ узнать в OnActionExecuted которому OnActionExecuting это соответствует? Если бы был какой-то уникальный идентификатор для действий, я мог бы использовать его как ключ к словарю для хранения любых объектов, связанных с действиями, таких как регистраторы и таймеры. Есть ли? Или какое-то другое решение?

2 ответа

Решение

Что касается веб-API, то System.Web.HttpContext.Current не всегда гарантировано. Это зависит от того, используете ли вы собственный веб-интерфейс или нет. Это главная причина того, что при переопределении System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuting вы не получаете свойство httpcontext на HttpActionContext параметр (в AspNet MVC вы делаете).

Лучший способ сделать то же самое actionContext.Request.Properties толковый словарь.

проверьте также этот ответ здесь

System.Web.HttpContext.Current.Items - это хранилище кэша для каждого запроса.
Вы можете безопасно добавить объект таймера в Items в методе OnBeforeAction и извлечь этот объект таймера из Items в методе OnAfterAction

Другие вопросы по тегам