测量调用 ASP.NET MVC 控制器操作的时间

问题描述 投票:0回答:5

MVC 4 应用程序的一些用户偶尔会遇到速度缓慢的情况。 想必并非每个用户每次遇到该问题时都会报告该问题。

我的想法是测量每个控制器操作所花费的时间,并记录超过规定时间的操作调用的详细信息,以方便进一步分析(以排除或排除服务器/代码问题)。

是否有一种方便的方法来执行此类测量,以便我可以避免向每个操作添加检测代码? 我目前没有在这个项目中使用 IOC,并且会犹豫是否引入它来解决这个问题。

有没有更好的方法来解决此类问题?

asp.net-mvc asp.net-mvc-4 asp.net-mvc-5
5个回答
45
投票

您可以创建一个全局操作过滤器吗? 像这样的东西:

public class PerformanceTestFilter : IActionFilter
{
    private Stopwatch stopWatch = new Stopwatch();

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        stopWatch.Reset();
        stopWatch.Start();
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        stopWatch.Stop();
        var executionTime = stopWatch.ElapsedMilliseconds;
        // Do something with the executionTime
    }
}

然后将其添加到 `Application_Start()' 中的

GlobalFilters
集合中

GlobalFilters.Filters.Add(new PerformanceTestFilter());

您可以从

filterContext
参数获取有关正在测试的控制器的详细信息。

更新

直接将过滤器添加到

GlobalFilters
集合将为所有操作创建过滤器的单个实例。 当然,这不适用于计时并发请求。 要为每个操作创建一个新实例,请创建一个过滤器提供程序:

public class PerformanceTestFilterProvider : IFilterProvider
{
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        return new[] {new Filter(new PerformanceTestFilter(), FilterScope.Global, 0)};
    }
}

然后不要直接添加过滤器,而是在

Application_Start()
中添加过滤器提供程序:

FilterProviders.Providers.Add(new PerformanceTestFilterProvider());

5
投票

我通常将这个简单的代码添加到布局视图的底部:

<!-- Page generated in @((DateTime.UtcNow - HttpContext.Current.Timestamp.ToUniversalTime()).TotalSeconds.ToString("F4")) s -->

输出类似:

<!-- Page generated in 0.4399 s -->

这会在创建

HttpContext
时开始测量(根据 文档),并在写入输出之前停止,因此它应该非常准确。

它可能不适用于所有用例(如果您想测量子操作,或忽略 MVC 操作之外的时间等),但它很容易粘贴到视图中。

对于更高级的诊断,我曾经使用Glimpse


1
投票

尝试 ASP.NET 4.5 页面检测

它检测页面渲染:应用程序的时间可能花在控制器上,但很多时候花在视图渲染上。特别是如果您有很多部分和 html 帮助程序。


0
投票

更新 - 使用 Install-Package StopWatch 安装我的 Stopwatch NuGet 包 请参阅在 Azure 中对 ASP.NET MVC 应用程序进行配置文件和计时

请参阅我的教程 在 ASP.NET MVC 4 中使用异步方法 它有一个全局动作过滤器计时器。您可以使用 ELMAH 来记录数据。我的示例 我的示例 http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98) 也具有相同的计时过滤器并且更简单,但它是 Razor 之前的版本。

查找秒表属性以启用计时。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new UseStopwatchAttribute());
    }
}

0
投票

如果您不想为每个请求创建一个新的过滤器实例,技巧是将开始时间添加到

context.HttpContext.Items
(对象字典)中。 MSDN

public class PerformanceFilter(ILoggerFactory loggerFactory) : IActionFilter
{
    const string StartTime = "REQ_START_TIME";
    ILogger<PerformanceFilter> Logger => loggerFactory.CreateLogger<PerformanceFilter>();

    public void OnActionExecuted(ActionExecutedContext context)
    {
        context.HttpContext.Items.Add(StartTime, Stopwatch.GetTimestamp());
        Logger.LogInformation("Request `{requestMethod} {requestPath}` has started", context.HttpContext.Request.Method, context.HttpContext.Request.Path);
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.HttpContext.Items.TryGetValue(StartTime, out var startTime))
        {
            var elapsedTime = Stopwatch.GetElapsedTime(Convert.ToInt64(startTime)).TotalSeconds;
            Logger.LogInformation("Request `{requestMethod} {requestPath}` has finished in `{elapsedTime}` s", context.HttpContext.Request.Method, context.HttpContext.Request.Path, elapsedTime);
        }
        else
        {
            Logger.LogInformation("Request `{requestMethod} {requestPath}` has finished", context.HttpContext.Request.Method, context.HttpContext.Request.Path);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.