ASP.NET Core MVC 中的慢速显示性能

Posted

技术标签:

【中文标题】ASP.NET Core MVC 中的慢速显示性能【英文标题】:Slow DisplayFor performance in ASP.NET Core MVC 【发布时间】:2017-02-23 00:37:17 【问题描述】:

在我当前的应用程序中,我正在生成一个相当长的表格来显示给用户。我一直看到它存在一些严重的性能问题,我已经追踪到使用 @html.DisplayFor,但我不完全确定原因。

编辑:我已将代码示例替换为更简洁和可重现的设置。

为了隔离问题,我使用 Visual Studio 中的所有默认设置创建了一个新的 asp.net core MVC 项目,没有进行身份验证。我这样创建了一个视图模型:

public class TestingViewModel

    public int Id  get; set; 
    public string TextValue1  get; set; 
    public string TextValue2  get; set; 

然后添加了一个控制器,它用数据填充视图模型以传递给视图:

    public IActionResult TestThings()
    
        var list = new List<TestingViewModel>();
        for(var i = 0; i < 1000; i++)
            list.Add(new TestingViewModel Id = i, TextValue1 = "Test", TextValue2 = "Test2");

        return View(list);
    

视图是显示数据的最低限度:

@model List<DisplayForTest.ViewModels.TestingViewModel>

@foreach (var item in Model)

    @Html.DisplayFor(m => item.Id)
    @Html.DisplayFor(m => item.TextValue1)
    @Html.DisplayFor(m => item.TextValue2)

运行此代码时,运行时间超过一秒!罪魁祸首是DisplayFor。如果我按如下方式更改视图:

@model List<DisplayForTest.ViewModels.TestingViewModel>

@foreach (var item in Model)

    @item.Id
    @item.TextValue1
    @item.TextValue2

这会在 13 毫秒内呈现。很明显,DisplayFor 正在为渲染增加大量时间……在我的 PC 上,每次调用将近 0.4 毫秒。虽然这在孤立的情况下还不错,但对于列表或其他事情来说,它是一个非常糟糕的选择。

DisplayFor 真的那么慢吗?还是我用错了?

【问题讨论】:

DisplayFor 使用反射来访问对象中的每个属性,如果它是导航属性,这可能会触发 EF 延迟加载。这可能是正在发生的事情。 您不应在视图中使用持久性模型的另一个原因,请改用视图模型。虽然我们不知道 OP 使用什么,但 EFCore 还没有实现延迟加载,只有 EF6 我为此使用 EFCore。我很快将其转换为视图模型,并使用members.Select(s =&gt; new MembersListViewModel Id = s.Id).ToList(); 选择了数据,但它似乎存在相同的性能问题。 实际上,跟进,使用视图模型大大提高了测试的性能,而不是使用显示,只需要5ms,但DisplayFor测试仍然需要400ms。所以感谢您的提示,但不幸的是,这并不是导致头痛的原因。 感谢您对 CodeCaster 的评论,我已经更新了该帖子,并至少需要重现它。我现在使用的代码基于默认模板(无身份验证),并且仅添加了一个控制器操作、视图和模型,并显示了所有代码。 【参考方案1】:

DisplayFor 真的有那么慢吗?还是我用错了?

计算和执行 lambda 表达式需要一些开销。首先框架必须validate it,然后是evaluate it。 我在这里推测了一下,但似乎这可能是性能问题的来源;这两种方法都需要反思。

我使用过的所有其他显示方法(ValueForDisplayTextFor 等)在您的示例中具有相同的性能效果。

我不能代表 MVC 团队说明为什么将它用于默认脚手架,但它对我来说确实有意义。 DisplayFor 可以处理两种最常见的用例(显示属性的值,以及使用自定义模板显示属性的值),并且在大多数情况下表现得相当好。

在这种情况下,我认为仅使用原始值(基本上是 .ToStringing 它)或在 Html.Encode/Html.Raw 方法中使用它没有问题,具体取决于您要查找的内容.

【讨论】:

是否可以得出这样的结论,对于不需要自定义显示模板的类型,DisplayFor 是矫枉过正?我很清楚,如果我希望在页面上显示这么多记录,我不能依赖它。使用 10 列,我渲染的每一行将使用 DisplayFor 占用服务器 4-5 毫秒,这是不可接受的。我确实尝试了ValueFor,虽然它快了一点,但它仍然很慢。我使用它的主要原因是脚手架会自动为您设置好它。如果这是预期的行为,我可以接受它作为答案。 @Doddler 你对ValueFor 的表现是正确的——我的回答有点离题。我已经更新了我的答案以更好地解决这个问题。 感谢您的帮助!在搞砸了一段时间之后,我倾向于直接输出常规类型,并使用 TagHelpers 或 HtmlHelpers 来显示更复杂的类型。我预计标签助手会产生一些成本,但它们似乎真的很有效。【参考方案2】:

在 Raspberry PI 上使用 .Net Core,我遇到了同样的问题。表演真的很糟糕。我使用了 dotTrace,发现反射使用了很多时间。

基于以下article,我能够加速应用程序。

【讨论】:

以上是关于ASP.NET Core MVC 中的慢速显示性能的主要内容,如果未能解决你的问题,请参考以下文章

数据存储到 ASP.NET Core 5 MVC 中的关联表

第 2 次、第 3 次 ASP.NET MVC 5 的慢速调试

EF Core 中的 ASP.NET Core 5 MVC 和 Identity - 基于资源的授权

将模型传递给 ASP.NET Core MVC 中的视图

如何使用 MS 数据库(ASP.NET Core MVC)通过表格显示信息?

使用 ASP.NET Core MVC 编辑 Cascade DropDownList