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

29

某些 MVC 4 应用的用户遇到了零星的缓慢问题。可能每个用户并不总是在出现该问题时都会报告。

我的想法是测量每个控制器动作所需的时间,并记录超过预设时间的动作调用详细信息,以便进一步分析(排除服务器/代码问题或确认存在问题)。

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

是否有更好的方法来解决这种类型的问题?

4个回答

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

听起来很有前途。我会试一试的。我猜每个操作都会创建一个PerformanceTestFilter实例(这样它就有自己的Stopwatch实例了),是吗? - Eric J.
实际上……它并不会。你需要针对此创建一个 IFilterProvider。请查看我的更新答案。 - Kevin Aenmey
3
提示:Stopwatch类有Restart方法。 - user1068352
1
你也可以使用 filterContext.HttpContext.Items 来存储你的计时器,并在之后获取它(对于 WebApi 过滤器,可以使用 actionContext.Request.Properties)。 - Guillaume86
3
有没有竞态条件?如果多个请求使用相同的过滤器实例 http://bradwilson.typepad.com/blog/2010/07/aspnet-mvc-filters-and-statefulness.html - Imran Qadir Baksh - Baloch
提示:在 OnActionExecuted 的末尾放置 stopWatch=null,这样您就可以确保获得一个新实例。如果出现异常,您就知道实例正在被重用。 - Simon_Weaver

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 安装我的秒表 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());
    }
}

我在教程中找不到全局操作过滤器。尝试搜索“全局”,“过滤器”和“计时器”,但没有结果。 - Brian Low
1
将全局过滤器添加到我的答案。 - RickAndMSFT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接