2014-03-20 1 views
2

Я создал фильтр действий для измерения времени выполнения каждого действия в веб-API v2.Как использовать ActionFilterAttribute для регистрации времени работы?

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" (они получают overriden)
  3. Действие Foo1 завершает выполнение. Он останавливает таймер и журналы, прошедшее время, которое бессмысленно (end1-start2).

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

ответ

6

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

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

жмите тоже этот ответ here

1

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