【问题标题】:How to get the elapsed time of a .NET WebAPI call如何获取 .NET WebAPI 调用的经过时间
【发布时间】:2016-05-31 19:07:40
【问题描述】:

如何在 C# 中获取 .NET WebAPI 调用的经过时间?

我的日志文件需要这些信息

我可以在 api 调用之前和之后轻松地做一个DateTime.Now(),但是,如果已经做了什么......让我们使用它!

【问题讨论】:

  • 我认为“经过的时间”概念是指TimeSpan 而不是DateTime。将Stopwatch 类与ElapsedMilliseconds 属性一起使用怎么样?

标签: c# datetime logging asp.net-web-api


【解决方案1】:

你可以使用过滤器

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Mvc;

namespace App.Utility
{
    /// <summary>
    /// Used to log requests to server
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class LogActionRequestsAttribute : ActionFilterAttribute
    {
        public LogActionRequestsAttribute()
        {
             //You can inject to constructors ILog or what ever
        }

        public static Stopwatch GetTimer(HttpRequestMessage request)
        {
            const string key = "__timer__";
            if (request.Properties.ContainsKey(key))
            {
                return (Stopwatch)request.Properties[key];
            }

            var result = new Stopwatch();
            request.Properties[key] = result;
            return result;
        }
        
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            
            var timer = GetTimer(actionContext.Request);
            timer.Start();
            base.OnActionExecuting(actionContext);
        }


        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
            var timer = GetTimer(actionExecutedContext.Request);
            timer.Stop();
            var totalTime = timer.ElapsedMilliseconds;            
        }
    }
}

然后在 webapi 配置中

config.Filters.Add(
                (LogActionRequestsAttribute)
                    GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof (LogActionRequestsAttribute)));

AttributeUsage 防止调用属性两次。 但我认为其他选项可能是你编写 http 模块来使用开始,结束请求事件,这可能是最好和精确的测量,在我的应用程序中它足以使用属性,因为几毫秒对我​​来说没什么大不了的

【讨论】:

  • 这很好用,但我发现如果有一个未处理的异常,那么 OnActionExecuted 永远不会被调用,所以我失去了该方法的时间。需要记住的一点是,如果您只需要成功的调用就可以了,否则您需要考虑实现一个 ExceptionHandler。
  • 注册过滤器时为什么调用GetService会导致null
【解决方案2】:

如果它对某人有帮助,我在下面添加了适用于 .NET Core 的 Vova 答案的更新版本。

/// <summary>
/// Used to log requests to server
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class LogActionRequestsAttribute : ActionFilterAttribute
{
    private const string ACTION = "Action";
    private const string RESULT = "Result";

    private static Stopwatch GetTimer(HttpContext context, string type)
    {
        var key = $"__timer__{type}";
        if (context.Items.ContainsKey(key)) return (Stopwatch) context.Items[key];
        var stopWatch = new Stopwatch();
        context.Items[key] = stopWatch;
        return stopWatch;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var timer = GetTimer(context.HttpContext, ACTION);
        timer.Start();
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        base.OnActionExecuted(context);
        var timer = GetTimer(context.HttpContext, ACTION);
        timer.Stop();

        var logger = context.HttpContext.RequestServices.GetService<ILogger<LogActionRequestsAttribute>>();
        logger.LogInformation($"{ACTION} call to {context.HttpContext.Request.Path} took {timer.ElapsedMilliseconds} ms");
    }

    public override void OnResultExecuting(ResultExecutingContext context)
    {
        var timer = GetTimer(context.HttpContext, RESULT);
        timer.Start();
        base.OnResultExecuting(context);
    }

    public override void OnResultExecuted(ResultExecutedContext context)
    {
        base.OnResultExecuted(context);
        var timer = GetTimer(context.HttpContext, RESULT);
        timer.Stop();

        var logger = context.HttpContext.RequestServices.GetService<ILogger<LogActionRequestsAttribute>>();
        logger.LogInformation($"{RESULT} call to {context.HttpContext.Request.Path} took {timer.ElapsedMilliseconds} ms");
    }
}

该属性可以直接应用于ApiController,无需额外注册。

【讨论】:

    猜你喜欢
    • 2019-01-26
    • 2023-04-05
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 2017-07-16
    • 2016-10-13
    • 1970-01-01
    • 2019-05-03
    相关资源
    最近更新 更多