6

我有一个相当简单的 ASP.MVC 视图的性能问题。

这是一个应该几乎是即时的登录页面,但大约需要半秒钟。

经过大量挖掘后,问题似乎是第一次调用Url.Action- 它大约需要 450 毫秒(根据 MiniProfiler ,但这似乎非常慢。

随后的调用时间Url.Action小于 1 毫秒,这更符合我的预期。

无论我使用Url.Action("action", "controller")Url.Action("action"),这都是一致的,但如果我使用 ,似乎不会发生Url.Content("~/controller/action")。当我打电话时也会发生这种情况Html.BeginForm("action")

有谁知道是什么原因造成的?

对源头的挖掘表明这RouteCollection.GetVirtualPath可能是罪魁祸首,因为这对Url.ActionHtml.BeginForm. 但是,肯定到处都在使用它吗?我的意思是,½ 秒太慢了。

我有 20 条左右的自定义路线(这是一个相当大的应用程序,带有一些旧版 WebForms 页面),但即便如此,时间似乎也太慢了。

任何想法如何解决它?

4

4 回答 4

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

事实证明,正则表达式检查非常缓慢,非常缓慢。因此,我将其替换为IRouteConstraint仅针对 a 进行检查的实现HashSet

然后我更改了地图路线调用:

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

我还将该链接文章中提到的 RegexConstraint用于更复杂的任何事情 - 包括许多这样的调用(因为我们有旧版 WebForm 页面):

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

这两个简单的更改完全解决了问题;Url.Action现在Html.BeginForm花费的时间可以忽略不计(即使有很多路线)。

于 2012-08-13T15:50:12.923 回答
1

在我看来,您的问题是编译视图。您需要在构建时预编译视图,这个问题就会消失。 详情在这里

于 2012-08-10T11:59:50.903 回答
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 + ")";
    }
}
于 2012-09-12T08:49:09.310 回答
0

与从 IHttpModule 下载相比,我已将其剥离为“简单”...将单个文件设置到内存中并从操作中下载它。由于某种原因(可能是MVC 管道加载、路由) ,IHttpModule 更快(对于小文件,例如产品列表图像)。我没有在路由中使用正则表达式(这会更慢)。在 IHttpModule 中,我达到的速度与 URL 指向驱动器上的文件的速度相同(当然,如果文件在驱动器上,但不在 URL 指向的驱动器位置上)。

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true">
     <add name="ImagesHandler" type="NsdMupWeb.ImagesHttpModule" />
  </modules>
</system.webServer>


//Code is made for testing
public class ImagesHttpModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += Context_BeginRequest;
    }

    private void Context_BeginRequest(object sender, EventArgs e)
    {
        var app = (HttpApplication)sender;
        if (app.Request.CurrentExecutionFilePathExtension.Length > 0)
        {
            var imagePathFormated = "/image/";
            var imagesPath = app.Request.ApplicationPath.TrimEnd('/') + imagePathFormated;
            if (app.Request.CurrentExecutionFilePath.StartsWith(imagesPath))
            {
                var path = app.Request.CurrentExecutionFilePath.Remove(0, imagesPath.Length);
                var parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length > 1)
                {
                    var ms = new MemoryStream();
                    Stream stream;

                    stream = System.IO.File.OpenRead(@"C:\Programming\Sindikat\Main\NsdMupWeb\Files\Cached\imageFormatProductList\1b1e2671-a365-4a87-97ba-063cf51ac34e.jpg");
                    var ctx = ((HttpApplication)sender).Context;
                    ctx.Response.ContentType = MimeMapping.GetMimeMapping(parts[1]);
                    ctx.Response.Headers.Add("last-modified", new DateTime(2000, 01, 01).ToUniversalTime().ToString("R"));

                    byte[] buffer = new byte[stream.Length / 2];
                    stream.Read(buffer, 0, buffer.Length);
                    ctx.Response.BinaryWrite(buffer);

                    buffer = new byte[stream.Length - buffer.Length];
                    stream.Read(buffer, 0, buffer.Length);
                    ctx.Response.BinaryWrite(buffer);
                    ctx.Response.End();
                }
            }
        }
    }
}
于 2019-12-05T21:59:16.817 回答