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 => new MembersListViewModel Id = s.Id).ToList();
选择了数据,但它似乎存在相同的性能问题。
实际上,跟进,使用视图模型大大提高了测试的性能,而不是使用显示,只需要5ms,但DisplayFor测试仍然需要400ms。所以感谢您的提示,但不幸的是,这并不是导致头痛的原因。
感谢您对 CodeCaster 的评论,我已经更新了该帖子,并至少需要重现它。我现在使用的代码基于默认模板(无身份验证),并且仅添加了一个控制器操作、视图和模型,并显示了所有代码。
【参考方案1】:
DisplayFor 真的有那么慢吗?还是我用错了?
计算和执行 lambda 表达式需要一些开销。首先框架必须validate it,然后是evaluate it。 我在这里推测了一下,但似乎这可能是性能问题的来源;这两种方法都需要反思。
我使用过的所有其他显示方法(ValueFor
、DisplayTextFor
等)在您的示例中具有相同的性能效果。
我不能代表 MVC 团队说明为什么将它用于默认脚手架,但它对我来说确实有意义。 DisplayFor
可以处理两种最常见的用例(显示属性的值,以及使用自定义模板显示属性的值),并且在大多数情况下表现得相当好。
在这种情况下,我认为仅使用原始值(基本上是 .ToString
ing 它)或在 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 - 基于资源的授权