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>
错误原因
- 控制器数据加载逻辑缺陷:遍历全表
TutorProfesionAndCost匹配用户ID,效率低下;且当用户无任何工作项记录时,ProfesionAndCosts为空列表,但页面直接访问索引0,触发越界。 - 页面硬编码索引:页面使用固定
@i=0访问列表元素,当列表为空时必然报错。 - 动态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
相关产品推荐
相关产品推荐

