8

Tengo una aplicación que actualicé recientemente de ASP.NET MVC1 a ASP.NET MVC4 rc1.Performance cuello de botella Url.Action - ¿puedo solucionarlo?

Utiliza Webforms viewengine.

Tiene problemas de rendimiento cuando se usa Url.Action (acción, controlador).

Puedo reproducir el problema en ASP.NET MVC3.

Necesito 3ms para renderizar vistas que tengan 10 instancias del ayudante Url.Action en ASP.NET MVC1 y 40ms para renderizar lo mismo en ASP.NET MVC3.

ya he encontrado algunas maneras de hacer que rinda más rápido:

  • I trasladó la ruta predeterminada a la parte superior

  • quité Url.Action y usados ​​enlaces estáticos

Esto no se siente bien: la aplicación es bastante grande y necesito la bondad de una ruta de trabajo decente en ella. Tampoco estoy seguro de haber encontrado todos los cuellos de botella en el rendimiento. El enrutamiento es una parte central de MVC: si hay algo que funciona mal aparecerá en diferentes partes de la aplicación.

Tengo la impresión de que MVC3 introdujo algunas características de enrutamiento (como restricciones de expresiones regulares) que, incluso si no las utilizo, conducen a una aplicación que no funciona bien.

¿Hay algo que pueda hacer como cambiar las características del enrutamiento o utilizar un conjunto diferente de URL-helpers?

Este código reproduce el problema:

acción Índice

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> 

Ruta de registro Esto parece extraño, pero sólo quiero para simular mi no es muy complicada enrutamiento ¡Estas no son las 600 rutas de 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" }); 
} 

EDITAR

El código de ejemplo que fue compilada en MVC2 ahora. En VS2010 MVC2 se puede compilar contra .NET 3.5 o 4.0.

El rendimiento con 3.5 es bueno y 4.0 es malo.

Supongo que esto significa que la parte de bajo rendimiento no está en un ensamblado MVC sino en un ensamblado de estructura (como System.Web.Routing.dll). La pregunta sigue siendo la misma: ¿puedo hacer algo al respecto? Una respuesta aceptada también sería: No, el código es lenta porque a partir de la versión 3,5 a 4,0 MS cambió XXX

EDITAR-2

I decompiled parte de System.Web.Routing.dll que lleva mucho tiempo. Utiliza una expresión regular compilada. Hay una ruta de código (constraint2.Match) que se devuelve sin ejecutar la expresión regular, pero no comprueve aún si internamente utiliza una operación costosa diferente.

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

¿Esto sucede en la primera solicitud o siempre? – dknaack

+0

La primera solicitud es más lenta, el tiempo que mides es la segunda solicitud. Y todo está en modo "lanzamiento". –

+0

¿Solo por curiosidad lo has probado sin todas las instrucciones de IgnoreRoute? – JTMon

Respuesta

3

Hay un problema resuelto similar al suyo: First call to Url.Action on a page is slow hay una conclusión sobre las restricciones de enrutamiento con las restricciones de expresiones regulares que es muy lenta.

+0

El uso de mi propia implementación de IRouteConstraint como se describe en la respuesta aceptada resolvió el problema. –

0

Cada vista se compila y almacena en caché cuando se utiliza por primera vez. Sin embargo, dado que las vistas de aspx no se diseñaron específicamente para Mvc, cada acción de Url.Action no se compila de una vez por todas en el enlace final, sino que se vuelve a calcular en cada ejecución. El compilador Razor tiene una mejor optimización. La única solución es calcular los diversos enlaces con la acción Url.Action y almacenarlos en alguna propiedad de nivel de aplicación, por lo que se calcula solo en la primera ejecución. Puede colocarlos en el diccionario de la aplicación o en propiedades estáticas de una clase.

0

No estoy seguro de la causa de lo que está viendo, pero puede no ser solo un MVC 1 vs MVC 4, la configuración de IIS en versiones posteriores puede afectar la velocidad de visualización de la vista. Me encontré con una presentación de diapositivas hace unos meses que pensé que era bastante interesante, en relación con los consejos de mejora del rendimiento en las aplicaciones de MVC 3.

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

Específicamente, echar un vistazo a la diapositiva 28, que establece:

desinstalar IIS UrlRewrite Módulo

  • Si no hay aplicaciones en el servidorestán utilizando
  • Sin efecto en aplicaciones MVC antes de v3
  • velocidad de Mejora de la generación de URL

tomo esto significa que el módulo UrlRewrite tendrá un impacto negativo MVC 3, pero no MVC 2 o 1, lo que podría ser una fuente de la desaceleración que está viendo. También hay otras mejoras, pero no creo que ninguna de ellas se relacione "directamente" con lo que está viendo.

Cuestiones relacionadas