Asp.net-Mvc-3

性能瓶頸 Url.Action - 我可以解決它嗎?

  • August 17, 2012

我有一個最近從 ASP.NET MVC1 升級到 ASP.NET MVC4 rc1 的應用程序。

它使用 Webforms 視圖引擎。

每當使用 Url.Action(action,controller) 時,它都會出現性能問題。

我可以在 ASP.NET MVC3 中重現該問題。

我需要 3 毫秒來呈現在 ASP.NET MVC1 中包含 10 個 Url.Action 幫助器實例的視圖,並且需要 40 毫秒來在 ASP.NET MVC3 中呈現相同的視圖。

我已經找到了一些讓它渲染得更快的方法:

  • 我將預設路由移到頂部
  • 我刪除了 Url.Action 並使用了靜態連結

這感覺不對:應用程序非常大,我需要其中的體面工作路由的優點。我也不相信我發現了所有的性能瓶頸。路由是 MVC 的核心部分:如果有什麼表現不好,它會在應用程序的不同部分彈出。

我的印像是 MVC3 引入了一些路由功能(如正則表達式約束),即使我不使用它們也會導致應用程序性能不佳。

有什麼我可以做的,比如打開路由功能或使用一組不同的 URL 助手?

此程式碼重現了該問題:

索引操作

public ActionResult Index()
       {

           return View();
       }

索引.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);
}

解決了與您類似的問題:在頁面上第一次呼叫 Url.Action 很慢 關於路由約束的結論與正則表達式約束非常慢。

每個視圖在第一次使用時都會被編譯和記憶體。但是,由於 aspx 視圖不是專門為 Mvc 設計的,因此每個 Url.Action 不會在最終連結中全部編譯一次,而是在每次執行時重新計算。Razor 編譯器有更好的優化。唯一的解決方案是使用 Url.Action 計算各種連結並將它們儲存到某個應用程序級別的屬性中,因此它僅在第一次執行時計算。您可以將它們放在應用程序字典或類的靜態屬性中。

引用自:https://stackoverflow.com/questions/11892335