8

Mam aplikację, którą niedawno zaktualizowałem z ASP.NET MVC1 do ASP.NET MVC4 rc1.Zatkanie wydajności Url.Action - czy mogę go obejść?

Wykorzystuje widok technologii Webforms.

Ma problemy z wydajnością, gdy używany jest Url.Action (działanie, kontroler).

Mogę odtworzyć problem w ASP.NET MVC3.

Potrzebuję 3ms, aby renderować widoki, które mają 10 wystąpień pomocnika Url.Action w ASP.NET MVC1 i 40 ms, aby renderować to samo w ASP.NET MVC3.

już znaleźć kilka sposobów, aby to uczynić szybciej:

  • przeprowadziłem domyślną trasę na górę

  • usunąłem Url.Action i używane statyczne linki

To nie jest w porządku: aplikacja jest dość duża i potrzebuję dobrej jakości przyzwoitego routingu. Nie jestem również pewien, że znalazłem wszystkie wąskie gardła wydajności. Routing jest centralną częścią MVC: jeśli coś działa źle, pojawi się w różnych częściach aplikacji.

Mam wrażenie, że MVC3 wprowadził pewne funkcje routingu (takie jak ograniczenia regex), które nawet jeśli ich nie używam, prowadzą do źle działającej aplikacji.

Czy jest coś, co mogę zrobić, jak włączyć funkcje routingu lub korzystać z innego zestawu pomocników adresów URL?

Ten kod reprodukuje problem:

działanie Index

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> 

Route rejestracja To wygląda dziwnie, lecz po prostu chcę symulować mój niezbyt skomplikowane routing. To nie jest 600 dróg 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

Kod próbki opracowano przeciwko MVC2 się. W VS2010 MVC2 można skompilować z .NET 3.5 lub 4.0.

Osiągi z 3.5 są dobre, a 4,0 złe.

Chyba oznacza to, że źle działająca część nie znajduje się w zespole MVC, ale w zespole szkieletowym (jak System.Web.Routing.dll). Pytanie wciąż jest takie samo: czy mogę coś z tym zrobić? Akceptowaną odpowiedź byłaby także: Nie, kod jest powolny, ponieważ od wersji 3.5 do 4.0 MS zmienił XXX

EDIT-2

I dekompilowana część System.Web.Routing.dll, która trwa długo. Używa skompilowanego wyrażenia regularnego. Istnieje ścieżka kodu (constraint2.Match), która zwraca się bez wykonywania regex, ale nie sprawdziłem jeszcze, czy wewnętrznie używa innej kosztownej operacji.

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

Czy dzieje się to na pierwsze żądanie lub za każdym razem? – dknaack

+0

Pierwsze żądanie jest wolniejsze, czas, o którym mówiono, jest drugim żądaniem. A wszystko to w trybie "wydania". –

+0

Po prostu z ciekawości próbowaliście go bez wszystkich instrukcji IgnoreRoute? – JTMon

Odpowiedz

3

Rozwiązany problem jest podobny do Twojego: First call to Url.Action on a page is slow Istnieją wnioski dotyczące ograniczeń routingu z ograniczeniami regexp, które są bardzo powolne.

+0

Używanie mojej własnej implementacji IRouteConstraint jak opisano w zaakceptowanej odpowiedzi rozwiązało problem. –

0

Każdy widok jest skompilowany i buforowane, gdy stosuje się go po raz pierwszy. Jednakże, ponieważ widoki aspx nie zostały zaprojektowane specjalnie dla Mvc, każdy Url.Action nie jest skompilowany raz dla wszystkich w ostatecznym łączu, ale jest ponownie obliczany przy każdym wykonaniu. Kompilator maszynki ma lepszą optymalizację. Jedynym rozwiązaniem jest obliczanie różnych linków za pomocą Url.Action i zapisywanie ich w niektórych właściwościach na poziomie aplikacji, więc jest obliczana tylko przy pierwszym uruchomieniu. Możesz umieścić je w słowniku aplikacji lub we właściwościach statycznych klasy.

0

Nie jestem pewien przyczyny tego, co widzisz, ale może to być nie tylko MVC 1 vs MVC 4, instalacja IIS w późniejszych wersjach może mieć wpływ na szybkość renderowania widoku. Kilka miesięcy temu natknąłem się na platformę slajdów, którą uważałem za interesującą, dotyczącą porad dotyczących poprawy wydajności w aplikacjach MVC 3.

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

szczególności spojrzeć na slajd 28, który stanowi:

Odinstaluj IIS UrlRewrite Module

  • Jeśli żadne aplikacje na serwerzeużywasz go
  • Brak efektu w aplikacjach MVC przed wersją 3
  • Zwiększa szybkość generowania adresów URL

biorę to oznaczać, że moduł UrlRewrite będzie negatywnie wpływać MVC 3, ale nie MVC 2 lub 1, które mogłyby być źródłem spowolnienia, które widzisz. Są też inne ulepszenia, ale nie wierzę, że którekolwiek z nich "bezpośrednio" odnoszą się do tego, co widzisz.

Powiązane problemy