You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Razor模型属性被重复调用数百次的性能问题排查

问题描述

我是ASP.NET Razor新手,可能存在概念误解。我实例化模型并从本地数据库获取数据返回视图,代码可正常运行,但模型的MainNodes属性的getter被调用数百次,严重影响性能。调试时发现,在视图中访问@Model.MainNodes[i].name时模型会被重建,请问这是什么原因?

控制器代码

public class GlobalTaggingController : BaseCmsEditorController
{
     public GlobalTaggingViewModel model = new GlobalTaggingViewModel();

     public ActionResult Index(string searchword = "")
     {
         return View(model);
     }

     // ... 省略部分代码
}

ViewModel代码

public class GlobalTaggingViewModel : BaseViewModel
{
    public List<NodeModel> MainNodes
    {
        get
        {
            var globalTaggingLocalizedManager = new GlobalTaggingLocalizationManager();
            var manager = new GlobalTaggingManager();
            var mainlevel = manager.GetAllItemsOnLevel(0);
            var subLevel = manager.GetAllItemsOnLevel(1);
            var subsubLevel = manager.GetAllItemsOnLevel(2);
            var resMainCat = new List<NodeModel>();

            // ... 省略部分代码
            return resMainCat;
        }
    }
}

视图代码(片段)

@model Application.Areas.Administration.Models.GlobalTaggingViewModel
@{ 
    ViewBag.Title = "Administration - Video";

    var positionNr = 0;
}


<form action="@Url.Action("Index")" method="POST" id="mainForm">
    <div class="divHeader Administration">
        <div class="divHeaderInner">

                @for (int i = 0; i < Model.MainNodes.Count(); i++)
                {
                    string catId = "CatId" + i.ToString();
                    string classToHideCatId = "classToHideCatId" + i.ToString();
                    string rowCounter = "rowCounter" + i.ToString();

                    <tr class="mainCatRow">
                        <td>
                            <table class="mytable">
                                <thead>

                                </thead>

                                <tr class="@rowCounter rowHeight">
                                    <td class="column0">
                                        <div>
                                            <img src="@Url.Content("~/Content/images/icons/icon-open.png")" id="@catId" class="buttonLayoutMain" />
                                        </div>
                                    </td>
                                    <td class="column1">
                                        <table class="tableInCol1">
                                            <tr>
                                                <td class="editButtonClassLeft">
                                                    <div class="mainCat">
                                                        @Model.MainNodes[i].name
                                                    </div>
                                                </td>
                                                <td class="editButtonClassRight">
                                                    <div>
                                                        <a onclick="javascript:Base.Popup.Open('@Url.Action("Index", "GlobalTaggingEditor", new {area = "Cms", id =  Model.MainNodes[i].Id})', 1236, 800); return false;" href="#" class="ButtonEdit"><span class="mif-pencil"></span></a>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].nameEng
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].name
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].nameSpanisch
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].nameFra
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].namePort
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @Model.MainNodes[i].nameRuss
                                        </div>
                                    <td class="column9">
原因分析与解决方案

核心原因

你当前的MainNodes是一个仅包含getter的计算属性,每次访问Model.MainNodes(包括调用Count()、通过[i]索引取值)都会执行getter内的全部逻辑:重新实例化管理器、查询数据库、构建新的List<NodeModel>。

结合你的视图代码:

  • 循环条件里的Model.MainNodes.Count() → 每次循环迭代都会触发一次getter
  • 循环体内多次调用Model.MainNodes[i].xxx → 每一次索引访问都会触发一次getter
    累计下来触发数百次调用完全符合逻辑,性能自然会受严重影响。

解决方法

方法1:懒加载+缓存结果

修改ViewModel,用私有字段缓存查询结果,仅在第一次访问时执行数据库查询:

public class GlobalTaggingViewModel : BaseViewModel
{
    private List<NodeModel> _mainNodes; // 私有字段缓存结果

    public List<NodeModel> MainNodes
    {
        get
        {
            if (_mainNodes == null) // 仅第一次访问时执行查询逻辑
            {
                var globalTaggingLocalizedManager = new GlobalTaggingLocalizationManager();
                var manager = new GlobalTaggingManager();
                var mainlevel = manager.GetAllItemsOnLevel(0);
                var subLevel = manager.GetAllItemsOnLevel(1);
                var subsubLevel = manager.GetAllItemsOnLevel(2);
                _mainNodes = new List<NodeModel>();

                // ... 省略部分代码
            }
            return _mainNodes;
        }
    }
}

方法2:控制器提前加载数据

把数据加载逻辑从ViewModel的getter移到控制器中,避免视图重复触发查询:

  1. 修改ViewModel为普通可赋值属性:
public class GlobalTaggingViewModel : BaseViewModel
{
    public List<NodeModel> MainNodes { get; set; }
}
  1. 控制器内提前查询并赋值:
public class GlobalTaggingController : BaseCmsEditorController
{
    public ActionResult Index(string searchword = "")
    {
        var model = new GlobalTaggingViewModel();
        // 提前执行数据加载逻辑
        var globalTaggingLocalizedManager = new GlobalTaggingLocalizationManager();
        var manager = new GlobalTaggingManager();
        var mainlevel = manager.GetAllItemsOnLevel(0);
        var subLevel = manager.GetAllItemsOnLevel(1);
        var subsubLevel = manager.GetAllItemsOnLevel(2);
        model.MainNodes = new List<NodeModel>();

        // ... 省略部分代码

        return View(model);
    }

    // ... 省略部分代码
}

方法3:视图内缓存局部变量

在视图开头将MainNodes缓存到局部变量,避免多次访问Model.MainNodes:

@model Application.Areas.Administration.Models.GlobalTaggingViewModel
@{ 
    ViewBag.Title = "Administration - Video";
    var positionNr = 0;
    var mainNodes = Model.MainNodes; // 缓存到局部变量,仅触发一次getter
}


<form action="@Url.Action("Index")" method="POST" id="mainForm">
    <div class="divHeader Administration">
        <div class="divHeaderInner">

                @for (int i = 0; i < mainNodes.Count(); i++)
                {
                    string catId = "CatId" + i.ToString();
                    string classToHideCatId = "classToHideCatId" + i.ToString();
                    string rowCounter = "rowCounter" + i.ToString();

                    <tr class="mainCatRow">
                        <td>
                            <table class="mytable">
                                <thead>

                                </thead>

                                <tr class="@rowCounter rowHeight">
                                    <td class="column0">
                                        <div>
                                            <img src="@Url.Content("~/Content/images/icons/icon-open.png")" id="@catId" class="buttonLayoutMain" />
                                        </div>
                                    </td>
                                    <td class="column1">
                                        <table class="tableInCol1">
                                            <tr>
                                                <td class="editButtonClassLeft">
                                                    <div class="mainCat">
                                                        @mainNodes[i].name
                                                    </div>
                                                </td>
                                                <td class="editButtonClassRight">
                                                    <div>
                                                        <a onclick="javascript:Base.Popup.Open('@Url.Action("Index", "GlobalTaggingEditor", new {area = "Cms", id =  mainNodes[i].Id})', 1236, 800); return false;" href="#" class="ButtonEdit"><span class="mif-pencil"></span></a>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].nameEng
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].name
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].nameSpanisch
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].nameFra
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].namePort
                                        </div>
                                    <td>
                                    <td>
                                        <div class="mainCat mainCol">
                                            @mainNodes[i].nameRuss
                                        </div>
                                    <td class="column9">

内容的提问来源于stack exchange,提问作者inno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 01:50:24