Как использовать 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
,
Например.
- Действие Foo1 начинает выполнение.
_logger = "logger1"
,_timer = "timer1"
, - Действие Foo2 начинает выполнение.
_logger = "logger2"
,_timer = "timer2"
(они переопределяются) - Действие 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