性能瓶頸 Url.Action - 我可以解決它嗎?
我有一個最近從 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 計算各種連結並將它們儲存到某個應用程序級別的屬性中,因此它僅在第一次執行時計算。您可以將它們放在應用程序字典或類的靜態屬性中。