C# 如何获取.NET WebAPI调用的运行时间

C# 如何获取.NET WebAPI调用的运行时间,c#,datetime,logging,asp.net-web-api,C#,Datetime,Logging,Asp.net Web Api,如何在C#中获取.NET WebAPI调用的运行时间 我的日志文件需要这些信息 我可以很容易地在api调用之前和之后做一个DateTime.Now(),但是,如果已经做了什么。。。让我们用它 您可以使用过滤器 using System; using System.Diagnostics; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using System.Web

如何在C#中获取
.NET WebAPI
调用的运行时间

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

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

您可以使用过滤器

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;            
        }
    }
}
AttributeUsage防止调用属性两次。
但我认为另一个选择可能是编写http模块来使用begin、end请求事件,这可能是最好和精确的测量方法,在我的应用程序中,使用属性就足够了,因为几毫秒对我来说并没有什么大不了的,以防它对某人有所帮助,我在下面添加了一个适用于.NETCore的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");
    }
}
//
///用于将请求记录到服务器
/// 
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
公共类LogActionRequestsAttribute:ActionFilterAttribute
{
private const string ACTION=“ACTION”;
private const string RESULT=“RESULT”;
私有静态秒表GetTimer(HttpContext上下文,字符串类型)
{
var key=$“\uuuu计时器\uuuu{type}”;
if(context.Items.ContainsKey(key))返回(秒表)context.Items[key];
var stopWatch=新秒表();
context.Items[键]=秒表;
返回秒表;
}
公共重写无效OnActionExecuting(ActionExecutingContext上下文)
{
var timer=GetTimer(context.HttpContext,ACTION);
timer.Start();
base.OnActionExecuting(上下文);
}
公共覆盖无效OnActionExecuted(ActionExecutedContext上下文)
{
base.OnActionExecuted(上下文);
var timer=GetTimer(context.HttpContext,ACTION);
timer.Stop();
var logger=context.HttpContext.RequestServices.GetService();
logger.LogInformation($“{ACTION}调用{context.HttpContext.Request.Path}花费了{timer.elapsedmillesons}毫秒”);
}
public override void OnResultExecuting(ResultExecutingContext)
{
var timer=GetTimer(context.HttpContext,RESULT);
timer.Start();
base.OnResultExecuting(上下文);
}
公共覆盖无效OnResultExecuted(ResultExecutedContext)
{
base.OnResultExecuted(上下文);
var timer=GetTimer(context.HttpContext,RESULT);
timer.Stop();
var logger=context.HttpContext.RequestServices.GetService();
logger.LogInformation($“{RESULT}调用{context.HttpContext.Request.Path}花费了{timer.elapsedmillesons}毫秒”);
}
}

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

我认为“已用时间”概念指的是
TimeSpan
,而不是
DateTime
。使用
Stopwatch
类及其
elapsedmillesons
属性如何?这很好,但我发现如果存在未处理的异常,则OnActionExecuted永远不会被调用,因此我失去了该方法的计时。需要记住的是,如果您只需要成功的调用,那么这很好,否则您需要考虑实现ExceptionHandler。为什么注册筛选器时对
GetService
的调用会导致
null
/// <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");
    }
}