1

我想创建一个简单的全局变量,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);
    }
}

如您所见,我使用 aStopwatch作为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

4

1 回答 1

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 ,它是独立于请求的.

于 2015-08-03T21:21:15.287 回答