I created an action filter for measuring running times of every action in an 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);
}
}
However, action filters act as singletons, so when OnActionExecuted
runs, I cannot be sure that the _logger
and _timer
correspond to the ones created for the same action OnActionExecuting
.
Eg.
_logger = "logger1"
, _timer = "timer1"
._logger = "logger2"
, _timer = "timer2"
(they get overriden)Question: Is there a way I can know in OnActionExecuted
to which OnActionExecuting
it corresponds? If there was some unique identifier for actions, I could use it as a key to a Dictionary to store any action-related objects such as loggers and timers. Is there any? Or some other solution?
ASP.NET MVC provides Action Filters for executing filtering logic either before or after an action method is called. Action Filters are custom attributes that provide declarative means to add pre-action and post-action behavior to the controller's action methods.
Action filters contain logic that is executed before and after a controller action executes. You can use an action filter, for instance, to modify the view data that a controller action returns. Result filters contain logic that is executed before and after a view result is executed.
ActionExecutingContext(ControllerContext, ActionDescriptor, IDictionary<String,Object>) Initializes a new instance of the ActionExecutingContext class by using the specified controller context, action descriptor, and action-method parameters.
As far as Web API is concerned the System.Web.HttpContext.Current
is not always guaranteed. It depends on whether you are using Web API Self hosted or not. That is the main reason that when overriding System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuting
you don't get an httpcontext property on the HttpActionContext
parameter (In AspNet MVC you do).
The best way to do the same is the actionContext.Request.Properties
dictionary.
check also this answer here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With