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

ASP.NET Core MVC 3.0编辑页列表显示报错:ArgumentOutOfRangeException

问题:编辑页面加载时抛出ArgumentOutOfRangeException异常

进入编辑页面时触发错误:
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
场景为实现用户填写多项工作内容及对应价格的列表功能,加载编辑页时出现索引越界。

相关代码

控制器代码

User user = await _userManager.FindByNameAsync(User.Identity.Name);
foreach(var up in _context.TutorProfesionAndCosts.ToList())
{
    if (user.Id == up.UserId)
        user.ProfesionAndCosts.Add(up);
}

User模型

public List<TutorProfesionAndCost> ProfesionAndCosts { get; set; }

public User()
{
    ProfesionAndCosts = new List<TutorProfesionAndCost>();
}

工作项模型(TutorProfesionAndCost)

public class TutorProfesionAndCost
{
    public int Id { get; set; }

    public string UserId { get; set; }
    public User User { get; set; }
    
    public string EducationalSubject { get; set; }

    public int Cost_One { get; set; } 
    public int Cost_Group { get; set; } 

    public string Currency { get; set; }
}

编辑页面代码

@{int i = 0;} 

<p>
    <div class="row">
        <div class="col">
            <label class="mb-0">Оберіть предмет який ви викладаєте:</label>
            <select asp-for="@Model.Tutor.ProfesionAndCosts[@i].EducationalSubject" required="required">
                @foreach (var profesion in Model.educational_Subject)
                {
                    <option value="@profesion.EducationalSubject">@profesion.EducationalSubject</option>
                }
            </select>
        </div>
        <div class="col">
            <label>Вкажіть вартість за 1 годину:</label>
            <p>
                <span>Індивідуальне заняття: <input class="money" type="text" asp-for="@Model.Tutor.ProfesionAndCosts[@i].Cost_One" /> </span>
                <span>Групове заняття: <input class="money" type="text" asp-for="@Model.Tutor.ProfesionAndCosts[@i].Cost_Group" /> </span>
                <select asp-for="@Model.Tutor.ProfesionAndCosts[@i].Currency">
                    @foreach (var cur in Model.currency)
                    {
                        <option value="@cur.CurrencyMoney">@cur.CurrencyMoney</option>
                    }
                </select>
            </p>
        </div>
    </div>

    <button onclick="addSubject()">New</button>
</p>

动态添加项的JavaScript代码

<script>
function addSubject() {
    var index = document.querySelectorAll('.row').length;
    var html = `<div class="row">
        <div class="col">
            <label class="mb-0">Оберіть предмет який ви викладаєте:</label>
            <select asp-for="@@Model.Tutor.ProfesionAndCosts[${index}].EducationalSubject" required="required">
                @foreach (var profesion in Model.educational_Subject)
                {
                    <option value="@profesion.EducationalSubject">@profesion.EducationalSubject</option>
                }
            </select>
        </div>
        <div class="col">
            <label>Вкажіть вартість за 1 годину:</label>
            <p>
                <span>Індивідуальне заняття: <input class="money" type="text" asp-for="@@Model.Tutor.ProfesionAndCosts[${index}].Cost_One" /> </span>
                <span>Групове заняття: <input class="money" type="text" asp-for="@@Model.Tutor.ProfesionAndCosts[${index}].Cost_Group" /> </span>
                <select asp-for="@@Model.Tutor.ProfesionAndCosts[${index}].Currency">
                    @foreach(var cur in Model.currency)
                    {
                        <option value="@cur.CurrencyMoney">@cur.CurrencyMoney</option>
                    }
                </select>
            </p>
        </div>
    </div>`;
    $('#subjects').append(html);
    i = index + 1;
}
</script>

错误原因

  1. 控制器数据加载逻辑缺陷:遍历全表TutorProfesionAndCost匹配用户ID,效率低下;且当用户无任何工作项记录时,ProfesionAndCosts为空列表,但页面直接访问索引0,触发越界。
  2. 页面硬编码索引:页面使用固定@i=0访问列表元素,当列表为空时必然报错。
  3. 动态JS的Razor语法错误:JS中使用asp-for的写法无效,因为Razor是服务器端渲染,客户端JS无法解析该语法,导致生成的表单字段不符合模型绑定规范。

修复方案

1. 修正控制器数据加载逻辑

改用EF查询直接获取当前用户的工作项,并确保列表为空时添加一个空实例,避免页面索引越界:

User user = await _userManager.FindByNameAsync(User.Identity.Name);
// 直接查询当前用户的工作项,避免遍历全表
var userProfessions = await _context.TutorProfesionAndCosts
    .Where(up => up.UserId == user.Id)
    .ToListAsync();

foreach(var up in userProfessions)
{
    user.ProfesionAndCosts.Add(up);
}

// 空列表时添加一个空实例,保证页面能渲染初始项
if (!user.ProfesionAndCosts.Any())
{
    user.ProfesionAndCosts.Add(new TutorProfesionAndCost());
}

2. 修改编辑页面,循环渲染现有项

不再硬编码索引,而是遍历ProfesionAndCosts列表渲染所有项,同时保留选中状态:

<div id="subjects">
    @foreach (var item in Model.Tutor.ProfesionAndCosts)
    {
        var index = Model.Tutor.ProfesionAndCosts.IndexOf(item);
        <div class="row">
            <div class="col">
                <label class="mb-0">Оберіть предмет який ви викладаєте:</label>
                <select asp-for="@Model.Tutor.ProfesionAndCosts[index].EducationalSubject" required="required">
                    @foreach (var profesion in Model.educational_Subject)
                    {
                        <option value="@profesion.EducationalSubject" 
                            @(profesion.EducationalSubject == item.EducationalSubject ? "selected" : "")>
                            @profesion.EducationalSubject
                        </option>
                    }
                </select>
            </div>
            <div class="col">
                <label>Вкажіть вартість за 1 годину:</label>
                <p>
                    <span>Індивідуальне заняття: <input class="money" type="text" asp-for="@Model.Tutor.ProfesionAndCosts[index].Cost_One" /> </span>
                    <span>Групове заняття: <input class="money" type="text" asp-for="@Model.Tutor.ProfesionAndCosts[index].Cost_Group" /> </span>
                    <select asp-for="@Model.Tutor.ProfesionAndCosts[index].Currency">
                        @foreach (var cur in Model.currency)
                        {
                            <option value="@cur.CurrencyMoney" 
                                @(cur.CurrencyMoney == item.Currency ? "selected" : "")>
                                @cur.CurrencyMoney
                            </option>
                        }
                    </select>
                </p>
            </div>
        </div>
    }
</div>

<button onclick="addSubject()">New</button>

3. 修正动态添加项的JS代码

手动生成符合模型绑定规范的name属性,避免在JS中使用Razor的asp-for:

<script>
function addSubject() {
    var subjectsContainer = document.getElementById('subjects');
    var index = subjectsContainer.querySelectorAll('.row').length;
    
    // 预渲染下拉选项的HTML片段
    var subjectOptions = '@foreach (var profesion in Model.educational_Subject) { <option value="@profesion.EducationalSubject">@profesion.EducationalSubject</option> }';
    var currencyOptions = '@foreach(var cur in Model.currency) { <option value="@cur.CurrencyMoney">@cur.CurrencyMoney</option> }';
    
    var newRowHtml = `
        <div class="row">
            <div class="col">
                <label class="mb-0">Оберіть предмет який ви викладаєте:</label>
                <select name="Tutor.ProfesionAndCosts[${index}].EducationalSubject" required="required">
                    ${subjectOptions}
                </select>
            </div>
            <div class="col">
                <label>Вкажіть вартість за 1 годину:</label>
                <p>
                    <span>Індивідуальне заняття: <input class="money" type="text" name="Tutor.ProfesionAndCosts[${index}].Cost_One" /> </span>
                    <span>Групове заняття: <input class="money" type="text" name="Tutor.ProfesionAndCosts[${index}].Cost_Group" /> </span>
                    <select name="Tutor.ProfesionAndCosts[${index}].Currency">
                        ${currencyOptions}
                    </select>
                </p>
            </div>
        </div>`;
    
    subjectsContainer.insertAdjacentHTML('beforeend', newRowHtml);
}
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:27:01