2012-08-10 44 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