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

Posted

技术标签:

【中文标题】测量调用 ASP.NET MVC 控制器操作的时间【英文标题】:Measure Time Invoking ASP.NET MVC Controller Actions 【发布时间】:2012-07-06 09:04:58 【问题描述】:

MVC 4 应用程序的一些用户遇到了零星的缓慢。大概不是每个用户每次遇到这个问题时都会报告。

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

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

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

【问题讨论】:

【参考方案1】:

您能创建一个全局操作过滤器吗?像这样的:

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());

【讨论】:

听起来很有希望。我会试一试。为我假设的每个操作创建一个 PerformanceTestFilter 实例(以便它拥有自己的 Stopwatch 实例)? 其实......它没有。您需要为此创建一个IFilterProvider。请参阅我的更新答案。 提示:StopwatchRestart 方法。 您也可以使用filterContext.HttpContext.Items 来存储您的秒表并在之后取回(以及actionContext.Request.Properties 用于WebApi 过滤器)。 不存在竞争条件吗?如果多个请求使用同一个过滤器实例bradwilson.typepad.com/blog/2010/07/…【参考方案2】:

更新 - 使用 Install-Package StopWatch 安装我的 Stopwatch NuGet 包 见Profile and Time your ASP.NET MVC app all the way to Azure

看我的教程Using Asynchronous Methods in 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());
    

【讨论】:

我在教程中找不到全局操作过滤器。尝试搜索“全局”、“过滤器”和“计时器”,但均未命中。 在我的答案中添加了全局过滤器【参考方案3】:

试试ASP.NET 4.5 Page Instrumentation

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

【讨论】:

【参考方案4】:

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

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

输出类似:

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

这开始测量HttpContext 的创建时间(根据the documentation),并在写入输出之前停止,因此它应该非常准确。

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

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

【讨论】:

以上是关于测量调用 ASP.NET MVC 控制器操作的时间的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ASP.NET MVC 的视图中调用多个操作?

ASP.NET MVC:如何防止会话锁定?

使用 ASP.NET MVC 4 从控制器调用另一个不同的视图

ASP.NET MVC API 操作返回 404,所有其他操作都有效

ASP.NET MVC RedirectToAction 不刷新页面

来自 Javascript AJAX 的 ASP.NET MVC 操作调用收到 500 内部服务器错误