我想创建一个简单的全局ActionFilterAttribute
,它会告诉我所请求的资源以及运行所需的时间。这是迄今为止的代码:
public class APITraceAttribute : ActionFilterAttribute
{
private readonly Stopwatch timer;
public APITraceAttribute()
{
timer = new Stopwatch();
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
timer.Restart();
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
timer.Stop();
trace(actionExecutedContext.ActionContext, timer.Elapsed);
base.OnActionExecuted(actionExecutedContext);
}
private static void trace(HttpActionContext actionContext, TimeSpan duration)
{
HttpMethod method = actionContext.Request.Method;
string path = actionContext.Request.RequestUri.PathAndQuery;
string controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
string actionName = actionContext.ActionDescriptor.ActionName;
double totalSeconds = duration.TotalSeconds;
ILogger logger = new Logger("trace");
logger.Trace("{0} {1}: {2}Controller.{3} ({4:N4} seconds)...", method, path, controllerName, actionName, totalSeconds);
}
}
正如您所看到的,我使用Stopwatch
作为支持字段,我在行动开始时Restart
,在行动结束时使用Stop
。我不需要很高的精度,所以这很好。
但是,我通过编辑/App_Start/WebApiConfig.cs
文件来连接所有请求:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new APITraceAttribute());
}
}
我注意到这需要一个构造属性。这使我担心它将全面重用相同的属性实例,并且两个并发处理请求可能会尝试使用相同的Stopwatch
实例。是这样的吗?如何确保每个请求都有自己的Stopwatch
实例?
答案 0 :(得分:1)
您可以使用HttpContext.Current.Items
我认为可以安全地说它会按照请求存储。
试试这个
public override void OnActionExecuting(HttpActionContext actionContext)
{
var timer = HttpContext.Current.Items["timer"] as Stopwatch;
if (timer == null)
{
timer = new Stopwatch();
HttpContext.Current.Items["timer"] = timer;
}
timer.Restart();
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var timer = HttpContext.Current.Items["timer"] as Stopwatch;
timer.Stop();
trace(actionExecutedContext.ActionContext, timer.Elapsed);
base.OnActionExecuted(actionExecutedContext);
}
我正在OnActionExecuting中创建Stopwatch对象,因为正如你所说的那样,过滤器的实例可以在请求之间共享,并且在构造函数中创建它是不安全的,所以每次OnActionExecuting触发它时都会使用HttpContext.Current wich请求独立。