2012-08-10 19 views
6

我有一個相當簡單的ASP.MVC視圖的性能問題。在網頁上首次調用Url.Action

這是一個應該幾乎是即時的登錄頁面,但需要大約半秒。

經過大量的挖掘,它看起來像問題是第一個電話Url.Action - 它需要大約450毫秒(根據MiniProfiler),但似乎非常緩慢。

隨後撥打Url.Action的時間爲< 1ms,這更符合我的預期。

無論我使用Url.Action("action", "controller")還是Url.Action("action"),這都是一致的,但如果使用Url.Content("~/controller/action")似乎不會發生。這也發生在我撥打Html.BeginForm("action")時。

有沒有人有任何想法是什麼造成這個?

調侃到source表明RouteCollection.GetVirtualPath可能是罪魁禍首,因爲這是常見的兩種Url.ActionHtml.BeginForm。但是,這肯定會在各地使用?我的意思是,半秒鐘太慢了。

我有20個左右的自定義路由(這是一個相當大的應用程序與一些遺留的WebForms頁面),但即使如此,時間似乎太慢了。

任何想法如何解決它?

回答

5

發現問題,並且它是與路由表(歡呼基里爾)。

基本上我們有很多途徑的,看起來是這樣的:

string[] controllers = GetListOfValidControllers(); 

routes.MapRoute(
    name: GetRouteName(), 
    url: subfolder + "/{controller}/{action}/{id}", 
    defaults: new { action = "Index", id = UrlParameter.Optional }, 
    constraints: new { controller = "(" + string.Join("|", controllers) + ")" }); 

事實證明,the Regex check is very slow,痛苦的緩慢。所以我用一個IRouteConstraint的實現替換它,它只是針對HashSet進行檢查。

然後,我改變地圖上的路線呼叫:

routes.MapRoute(
    name: GetRouteName(), 
    url: subfolder + "/{controller}/{action}/{id}", 
    defaults: new { action = "Index", id = UrlParameter.Optional }, 
    constraints: new { controller = new HashSetConstraint(controllers) }); 

我還使用了RegexConstraint mentioned in that linked article任何東西更復雜 - 包括很多像這樣的電話(因爲我們有傳統的WebForm頁):

routes.IgnoreRoute(
    url: "{*allaspx}", 
    constraints: new { allaspx = new RegexConstraint(@".*\.as[pmh]x(/.*)?") }); 

這兩個簡單的改變就完全解決了這個問題。 Url.ActionHtml.BeginForm現在花費的時間可以忽略不計(即使有很多路線)。

1

在我看來,你的問題是編譯的意見。您需要預編譯構建視圖,此問題將消失。 details here

+0

這不會預編譯視圖,只是編譯後編譯它們,所以你得到構建錯誤,而不是運行時錯誤。它也沒有什麼區別 - 我在第一個Url.Action調用中仍然看到450ms左右。 – Keith 2012-08-10 13:03:22

+0

使用ASPNet_Compiler.exe可以進行適當的預編譯(請參閱http://msdn.microsoft.com/zh-cn/library/ms229863(v=vs.80).aspx),但即使沒有那個時間我就會看到'網址。Action'非常瘋狂 - 它幾乎就像是在每次頁面運行時發現控制器動作的完整反射。 – Keith 2012-08-10 13:36:49

+0

你能顯示你的RegisterRoutes(來自global.asax)嗎?它可以利用你的時間。 – 2012-08-10 14:19:31

1
public class RegexConstraint : IRouteConstraint, IEquatable<RegexConstraint> 
    { 
    Regex regex; 
    string pattern; 

    public RegexConstraint(string pattern, RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase) 
    { 
     regex = new Regex(pattern, options); 
     this.pattern = pattern; 
    } 

    public bool Match(System.Web.HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     object val; 
     values.TryGetValue(parameterName, out val); 
     string input = Convert.ToString(val, CultureInfo.InvariantCulture); 
     return regex.IsMatch(input); 
    } 

    public string Pattern 
    { 
     get 
     { 
      return pattern; 
     } 
    } 

    public RegexOptions RegexOptions 
    { 
     get 
     { 
      return regex.Options; 
     } 
    } 

    private string Key 
    { 
     get 
     { 
      return regex.Options.ToString() + " | " + pattern; 
     } 
    } 

    public override int GetHashCode() 
    { 
     return Key.GetHashCode(); 
    } 

    public override bool Equals(object obj) 
    { 
     var other = obj as RegexConstraint; 
     if (other == null) return false; 
     return Key == other.Key; 
    } 

    public bool Equals(RegexConstraint other) 
    { 
     return this.Equals((object)other); 
    } 

    public override string ToString() 
    { 
     return "RegexConstraint (" + Pattern + ")"; 
    } 
} 
+0

這是另一個有用的實現,我使用http://samsaffron.com/archive/2011/10/13/optimising-asp-net-mvc3-routing – Keith 2012-09-13 08:53:31

相關問題