8

У меня есть приложение, которое я недавно обновил с ASP.NET MVC1 до ASP.NET MVC4 rc1.Узкое место производительности Url.Action - могу ли я обходным путем?

Он использует Viewview Webforms.

У этого есть проблемы с производительностью, когда используется Url.Action (действие, контроллер).

Я могу воспроизвести проблему в ASP.NET MVC3.

Мне нужно 3 мс для рендеринга представлений, в которых есть 10 экземпляров помощника Url.Action в ASP.NET MVC1 и 40ms для визуализации того же самого в ASP.NET MVC3.

Я уже нашел несколько способов сделать это делают быстрее:

  • Я переехал маршрут по умолчанию к началу

  • Я удалены Url.Action и используются статические ссылки

Это не очень хорошо: приложение довольно большое, и мне нужна доброта достойной рабочей маршрутизации. Я также не уверен, что нашел все узкие места в производительности. Маршрутизация является центральной частью MVC: если есть что-то плохое, она появится в разных частях приложения.

У меня создалось впечатление, что MVC3 представил некоторые функции маршрутизации (например, ограничения регулярных выражений), которые даже если я их не использую, приводят к плохо выполняющемуся приложению.

Есть ли что-то, что я могу сделать, как поворот функций маршрутизации или использование другого набора URL-помощников?

Этот код воспроизводит вопрос:

Индекс действия

public ActionResult Index() 
     { 

      return View(); 
     } 

index.aspx

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head > 
    <title></title> 
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" /> 
</head> 

<body> 
    <div class="page"> 
<%= Url.Action("Action1", "Controller1") %> 
<%= Url.Action("Action2", "Controller2") %> 
<%= Url.Action("Action3", "Controller3") %> 
<%= Url.Action("Action4", "Controller4") %> 
<%= Url.Action("Action5", "Controller5") %> 
<%= Url.Action("Action6", "Controller6") %> 
<%= Url.Action("Action7", "Controller7") %> 
<%= Url.Action("Action8", "Controller8") %> 
<%= Url.Action("Action9", "Controller9") %> 
<%= Url.Action("Action10", "Controller10") %> 
    </div> 
</body> 
</html> 

Маршрут регистрации Это выглядит странно: но я просто хочу, чтобы имитировать мой не очень сложно маршрутизации. Это не 600 маршрутов SO!

public static void RegisterRoutesSlow(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    routes.IgnoreRoute("{language}/Content/{*pathInfo}"); 

    routes.IgnoreRoute("images/{*pathinfo}"); 
    routes.IgnoreRoute("scripts/{*pathinfo}"); 
    routes.IgnoreRoute("content/{*pathinfo}"); 
    routes.IgnoreRoute("{file}.gif"); 
    routes.IgnoreRoute("{file}.jpg"); 
    routes.IgnoreRoute("{file}.js"); 
    routes.IgnoreRoute("{file}.css"); 
    routes.IgnoreRoute("{file}.png"); 
    routes.IgnoreRoute("{file}.pdf"); 
    routes.IgnoreRoute("{file}.htm"); 
    routes.IgnoreRoute("{file}.html"); 
    routes.IgnoreRoute("{file}.swf"); 
    routes.IgnoreRoute("{file}.txt"); 
    routes.IgnoreRoute("{file}.xml"); 
    routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" }); 

    for (int i = 0; i <= 10; i++) 
    { 
     routes.MapRoute(
      // Route name 
      "RouteName" + i.ToString(), 
      // URL with parameters        
      "{language}/{controller}/{action}/{para1}", 
      // Parameter defaults 
      new 
      { 
       action = "Index", 
       language = "de", 
       para1 = 0 
      }, 
      //Parameter constraints 
      new { language = "de|en", controller = "SomeNameOfAnActualController" + i.ToString() } 
      ); 
    } 
    routes.MapRoute(
        "DefaulRoute",   // Route name 
        "{controller}/{action}", // URL with parameters 
        new 
        { 
         controller = "Home", 
         action = "Index", 
        } 
       ); 
    routes.MapRoute("404-PageNotFound", "{*url}", new { controller = "Error", action = "PageNotFound", language = "de" }); 
} 

EDIT

Код образца был составлен против MVC2 в настоящее время. В VS2010 MVC2 может быть скомпилирован против .NET 3.5 или 4.0.

Производительность 3.5 хорошая и 4.0 плохо.

Я думаю, это означает, что плохо выполняющая часть не находится в сборке MVC, а в сборке фреймов (например, System.Web.Routing.dll). Вопрос все тот же: могу ли я что-то сделать? Принятый ответ также будет: Нет, код медленно, потому что, начиная с версии 3.5 до 4.0 MS изменили XXX

EDIT-2

Я декомпилировал часть System.Web.Routing.dll, которая длится долго. Он использует скомпилированное регулярное выражение. Существует путь к коду (constraint2.Match), который возвращается без выполнения регулярного выражения, но я еще не проверял, использует ли он другую дорогостоящую операцию.

protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
{ 
    object obj2; 
    IRouteConstraint constraint2 = constraint as IRouteConstraint; 
    if (constraint2 != null) 
    { 
     return constraint2.Match(httpContext, this, parameterName, values, routeDirection); 
    } 
    string str = constraint as string; 
    if (str == null) 
    { 
     throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url })); 
    } 
    values.TryGetValue(parameterName, out obj2); 
    string input = Convert.ToString(obj2, CultureInfo.InvariantCulture); 
    string pattern = "^(" + str + ")$"; 
    return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase); 
} 
+0

Это происходит по первому запросу или в любое время? – dknaack

+0

Первый запрос медленнее, время, которое я получил, является вторым запросом. И все это в режиме «выпуска». –

+0

Просто из любопытства вы пробовали это без всех инструкций IgnoreRoute? – JTMon

ответ

3

Решена проблема, аналогичная вашей: First call to Url.Action on a page is slow есть вывод о ограничениях маршрутизации с ограничениями регулярного выражения, которые очень медленны.

+0

Использование моей собственной реализации IRouteConstraint, как описано в принятом ответе, решило проблему. –

0

Каждое представление скомпилировано и кэшировано, когда оно используется в первый раз. Однако, поскольку представления aspx не были специально разработаны для Mvc, каждый Url.Action не компилируется один раз для всех в финальной ссылке, но он переустанавливается при каждом выполнении. Компилятор Razor имеет лучшую оптимизацию. Единственное решение - вычисление различных ссылок с помощью Url.Action и сохранение их в некотором свойстве уровня приложения, поэтому оно вычисляется только при первом выполнении. Вы можете поместить их либо в словарь приложений, либо в статические свойства класса.

0

Я не уверен в причине того, что вы видите, но это может быть не только MVC 1 и MVC 4, настройка IIS в более поздних версиях может повлиять на скорость рендеринга представлений. Несколько месяцев назад я наткнулся на слайд-колоду, что, по моему мнению, было довольно интересным, связанным с советами по повышению производительности в приложениях MVC 3.

http://www.slideshare.net/ardalis/improving-aspnet-mvc-application-performance

В частности, обратите внимание на слайде 28, в котором говорится:

Удаление IIS UrlRewrite Модуль

  • Если нет приложений на сервере не используют его
  • Отсутствие эффекта в приложениях MVC до версии v3
  • Увеличивает скорость генерации URL

Я принимаю это означает, что модуль UrlRewrite будет отрицательно воздействовать на MVC 3, но не MVC 2 или 1, который может быть источником замедления, что вы видите. Есть и некоторые другие улучшения, но я не считаю, что любой из них «напрямую» относится к тому, что вы видите.