性能瓶颈Url.Action - 我可以解决它吗?

时间:2012-08-09 21:38:17

标签: asp.net-mvc-3 asp.net-mvc-2 asp.net-mvc-routing asp.net-4.0 asp.net-3.5

我有一个应用程序,我最近从ASP.NET MVC1升级到ASP.NET MVC4 rc1。

它使用Webforms视图引擎。

每当使用Url.Action(操作,控制器)时,都会出现性能问题。

我可以在ASP.NET MVC3中重现该问题。

我需要3ms来渲染在ASP.NET MVC1中有10个Url.Action帮助器实例的视图,在ASP.NET MVC3中渲染相同的40ms。

我已经找到一些方法让它渲染得更快:

  • 我将默认路线移至顶部

  • 我删除了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>

路线注册 这看起来很奇怪:但我只想模拟我不太复杂的路由。这不是SO的600条路线!

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" });
}

修改

示例代码现在是针对MVC2编译的。在VS2010中,MVC2可以针对.NET 3.5或4.0进行编译。

3.5的性能好,4.0差。

我想这意味着性能不佳的部分不在MVC程序集中,而是在框架程序集中(如System.Web.Routing.dll)。问题仍然是一样的:我能为此做些什么吗?一个接受的答案也是:不,代码很慢,因为从版本3.5到4.0 MS改变了XXX

修改-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);
}

3 个答案:

答案 0 :(得分:3)

解决了与您类似的问题:First call to Url.Action on a page is slow 关于路由约束的结论与正则表达式约束很慢。

答案 1 :(得分:0)

第一次使用时,每个视图都会被编译和缓存。但是,由于aspx Views不是专门为Mvc设计的,因此每个Url.Action在最终链接中都不是一次编译,而是在每次执行时重新计算。 Razor编译器有更好的优化。 唯一的解决方案是使用Url.Action计算各种链接并将它们存储到某个应用程序级属性中,因此只在第一次执行时计算它。您可以将它们放在Application字典中,也可以放在类的静态属性中。

答案 2 :(得分:0)

我不确定您所看到的原因,但它可能不仅仅是MVC 1 vs MVC 4,更高版本的IIS设置会影响视图渲染的速度。几个月前我遇到了一个幻灯片,我觉得这很有趣,与MVC 3应用程序中的性能改进技巧有关。

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

具体来说,请看幻灯片28,其中说明:

  

卸载IIS UrlRewrite Module

     
      
  • 如果服务器上没有应用程序正在使用它
  •   
  • v3之前的MVC应用程序没有效果
  •   
  • 提高网址生成速度
  •   

我认为这意味着UrlRewrite模块会对MVC 3产生负面影响,但不会对MVC 2或1产生负面影响,这可能是您所看到的减速源。还有一些其他的改进,但我不相信他们中的任何一个“直接”与你所看到的有关。

相关问题