Измерение времени вызова действий контроллера ASP.NET MVC

Некоторые пользователи приложения MVC 4 время от времени сталкиваются с медлительностью. Предположительно, не каждый пользователь сообщает об этой проблеме каждый раз, когда она с ними происходит.

Моя идея состоит в том, чтобы измерить время, затраченное на каждое действие контроллера, и зарегистрировать сведения о вызовах действий, которые превышают установленное время, чтобы облегчить дальнейший анализ (чтобы исключить или исключить проблему с сервером/кодом).

Есть ли удобный способ подключиться для выполнения таких измерений, чтобы я мог не добавлять инструментальный код к каждому действию? В настоящее время я не использую IOC для этого проекта и не решился бы представить его только для решения этой проблемы.

Есть ли лучший способ решить эту проблему?


person Eric J.    schedule 05.07.2012    source источник


Ответы (4)


Не могли бы вы создать глобальный фильтр действий? Что-то вроде этого:

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
    }
}

а затем добавьте его в свою коллекцию GlobalFilters в `Application_Start()'

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());
person Kevin Aenmey    schedule 05.07.2012
comment
Звучит многообещающе. Я попробую. Экземпляр PerformanceTestFilter создается для каждого действия, которое я предполагаю (чтобы у него был собственный экземпляр секундомера)? - person Eric J.; 06.07.2012
comment
На самом деле... нет. Для этого вам нужно создать IFilterProvider. Смотрите мой обновленный ответ. - person Kevin Aenmey; 06.07.2012
comment
Совет: Stopwatch имеет метод Restart. - person user1068352; 16.07.2014
comment
Вы также можете использовать filterContext.HttpContext.Items для хранения секундомера и последующего его возврата (и actionContext.Request.Properties для фильтров WebApi). - person Guillaume86; 16.04.2015
comment
Разве там нет состояния гонки? Если несколько запросов используют один и тот же экземпляр фильтра, bradwilson. typepad.com/blog/2010/07/ - person user960567; 28.04.2015
comment
Совет: поставьте stopWatch=null в конце OnActionExecuted, чтобы быть уверенным, что вы получаете новый экземпляр. Если вы получите исключение, вы будете знать, что экземпляр используется повторно. - person Simon_Weaver; 29.03.2017

Обычно я добавляю этот простой код в нижнюю часть окна макета:

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

Выводит что-то вроде:

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

Это начинается при создании HttpContext (согласно документация) и останавливается прямо перед записью в вывод, поэтому он должен быть достаточно точным.

Это может работать не во всех случаях использования (если вы хотите измерить дочерние действия или игнорировать время вне действия MVC и т. д.), но его легко вставить в представление.

Для более сложной диагностики я использовал Glimpse.

person Tom Pažourek    schedule 19.01.2017

Попробуйте Инструментарий страницы ASP.NET 4.5

Это инструментирует рендеринг страницы: время вашего приложения может быть потрачено в контроллере, но много раз оно тратится на рендеринг представления. Особенно, если у вас много партиалов и хелперов html.

person Mathias F    schedule 26.07.2014

Обновление: установите пакет NuGet секундомера с Install-Package StopWatch, см. Профиль и время вашего приложения ASP.NET MVC на всем пути к Azure

См. мой учебник Использование асинхронных методов в 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());
    }
}
person RickAndMSFT    schedule 06.07.2012
comment
Я не смог найти глобальный фильтр действий в учебнике. Пробовал искать глобальный, фильтр и таймер без совпадений. - person Brian Low; 25.07.2014
comment
добавил глобальный фильтр к моему ответу - person RickAndMSFT; 26.07.2014