8

Ho un'applicazione che ho recentemente aggiornato da ASP.NET MVC1 a ASP.NET MVC4 rc1.Bottleneck delle prestazioni Url.Action: posso aggirarlo?

Utilizza il motore di visualizzazione Webform.

Ha problemi di prestazioni ogni volta che si utilizza Url.Action (azione, controller).

Posso riprodurre il problema in ASP.NET MVC3.

Ho bisogno di 3 ms per eseguire il rendering di 10 istanze dell'heler Url.Action in esso in ASP.NET MVC1 e 40 ms per il rendering dello stesso in ASP.NET MVC3.

ho già trovato alcuni modi per rendere rendere più veloce:

  • ho spostato il percorso di default in cima

  • ho rimosso e utilizzato Url.Action collegamenti statici

Questo non mi sembra giusto: l'applicazione è abbastanza grande e ho bisogno della bontà di un instradamento funzionante decente. Non sono nemmeno sicuro di aver trovato tutti i colli di bottiglia delle prestazioni. Il routing è una parte centrale di MVC: se c'è qualcosa che si comporta male comparirà in diverse parti dell'applicazione.

Ho l'impressione che MVC3 abbia introdotto alcune caratteristiche di routing (come i vincoli di regex) che anche se non le uso, portano a un'applicazione mal funzionante.

C'è qualcosa che posso fare come la disattivazione delle funzionalità di routing o l'uso di un diverso set di URL-helpers?

Questo codice riproduce il problema:

azione Indice

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> 

percorso di registrazione Questo sembra strano: ma voglio solo simulare il mio non è molto complicato routing. Questo non è il 600 percorsi di 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

Il codice di esempio è stato compilato contro MVC2 ora. In VS2010 MVC2 può essere compilato con .NET 3.5 o 4.0.

Le prestazioni con 3.5 sono buone e 4,0 non sono buone.

Immagino che questo significhi che la parte con prestazioni scadenti non si trova in un assieme MVC ma in un assieme quadro (come System.Web.Routing.dll). La domanda è sempre la stessa: posso fare qualcosa al riguardo? Una risposta accettata sarebbe anche: No, il codice è lento perché dalla versione 3,5-4,0 MS cambiato XXX

EDIT-2

Ho decompilato la parte di System.Web.Routing.dll che dura a lungo. Usa un'espressione regolare compilata. Esiste un percorso di codice (constraint2.Match) che ritorna senza eseguire la regex, ma non ho ancora controllato se utilizza internamente un'operazione costosa diversa.

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

Questo succede alla prima richiesta o sempre? – dknaack

+0

La prima richiesta è più lenta, il tempo che ho misurato è la seconda richiesta. Ed è tutto in modalità "rilascio". –

+0

Solo per curiosità l'hai provato senza tutte le istruzioni di IgnoreRoute? – JTMon

risposta

3

Ci sono problemi risolti simili al tuo: First call to Url.Action on a page is slow ci sono conclusioni sui vincoli di instradamento con vincoli regexp che è molto lento.

+0

L'utilizzo della mia implementazione di IRouteConstraint come descritto nella risposta accettata ha risolto il problema. –

0

Ogni vista viene compilata e memorizzata nella cache quando viene utilizzata la prima volta. Tuttavia, poiché le viste aspx non sono state progettate specificamente per Mvc, ogni Url.Action non viene compilato una volta per tutte nel collegamento finale ma viene ricalcolato ad ogni esecuzione. Il compilatore Razor ha una migliore ottimizzazione. L'unica soluzione è il calcolo dei vari linkks con Url.Action e la loro memorizzazione in alcune proprietà a livello di applicazione, quindi viene calcolata solo alla prima esecuzione. È possibile inserirli nel dizionario dell'applicazione o nelle proprietà statiche di una classe.

0

Non sono sicuro della causa di ciò che si sta vedendo, ma potrebbe non solo essere un MVC 1 o MVC 4, l'installazione di IIS nelle versioni successive può influire sulla velocità del rendering della vista. Alcuni mesi fa mi sono imbattuto in un deck di diapositive che ritenevo piuttosto interessante, relativo ai suggerimenti per il miglioramento delle prestazioni nelle app MVC 3.

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

In particolare, dare un'occhiata a scorrimento 28, in cui si afferma:

Disinstallare IIS URLRewrite modulo

  • Se nessuna applicazione sul serverstanno usando
  • Nessun effetto nelle app MVC prima della v3
  • velocità migliora di generazione URL

prendo questo per significare che il modulo URLRewrite avrà un impatto negativo MVC 3, ma non MVC 2 o 1, che potrebbe essere una fonte di rallentamento che si sta vedendo. Ci sono anche altri miglioramenti, ma non credo che nessuno di questi 'direttamente' riguardi ciò che stai vedendo.