ASP.NET Core 6整合分页与排序过滤触发NullReferenceException求助
问题描述
完成分页功能开发后,加入旧代码的排序与过滤逻辑,程序抛出以下错误:
NullReferenceException: Object reference not set to an instance of an object.
怀疑问题出在分页使用Post方法、排序过滤使用Get方法,但不清楚具体修复方案。
控制器代码
public async Task<IActionResult> Index() { return View(await GetStudentList(1)); } [HttpPost] public async Task<IActionResult> Index(int currentPageIndex) { return View(await GetStudentList(currentPageIndex)); } // GET: Students public IActionResult IndexProses(string sortOrder, StudentVM model) { ViewData["CurrentSort"] = sortOrder; ViewData["NameSortParm"] = sortOrder == "name" ? "name_desc" : "name"; ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date"; ViewData["FirstSortParm"] = String.IsNullOrEmpty(sortOrder) ? "first_desc" : ""; ViewData["CurrentFilter"] = model.FirstMidName; ViewData["CurrentFilter2"] = model.LastName; ViewData["CurrentFilter3"] = model.EnrollmentDateFrom; ViewData["CurrentFilter3"] = model.EnrollmentDateUntil; var students = from s in _context.Students select s; // sorting // students = sortOrder switch { "name" => students.OrderBy(s => s.LastName),// asc last name "name_desc" => students.OrderByDescending(s => s.LastName),//desc last name "first_desc" => students.OrderByDescending(s => s.FirstMidName),// desc first name "Date" => students.OrderBy(s => s.EnrollmentDate),// asc date "date_desc" => students.OrderByDescending(s => s.EnrollmentDate),// desc date _ => students.OrderBy(s => s.FirstMidName),// asc first name }; // filtering if (model.EnrollmentDateFrom != null && model.EnrollmentDateUntil != null) { students = students.Where(s => s.EnrollmentDate >= model.EnrollmentDateFrom && s.EnrollmentDate <= model.EnrollmentDateUntil); } if (!String.IsNullOrEmpty(model.LastName)) { students = students.Where(s => s.LastName.Contains(model.LastName)); } if (!String.IsNullOrEmpty(model.FirstMidName)) { students = students.Where(s => s.FirstMidName.Contains(model.FirstMidName)); } return View("Index", model); } private async Task<StudentVM> GetStudentList(int currentPage) { int maxRowsPerPage = 5; StudentVM model = new StudentVM(); model.StundentList = await (from s in _context.Students select s) .Skip((currentPage - 1) * maxRowsPerPage) .Take(maxRowsPerPage).ToListAsync(); double pageCount = (double)((decimal)_context.Students.Count() / Convert.ToDecimal(maxRowsPerPage)); model.pageCount = (int)Math.Ceiling(pageCount); model.currentPageIndex = currentPage; return model; }
视图代码(Index.cshtml)
@model ContosoUniversity.Models.SchoolViewModels.StudentVM @{ ViewData["Title"] = "Students"; } <style> table{ margin-top: 20px; } .table a{ text-decoration: none; } h2{ margin-bottom: 20px; } .tbl{ display: flex; gap: 1rem; } .box{ display: flex; gap: 1rem; margin-bottom: 10px; } </style> <h2>Contoso University - Students</h2> <form asp-action="IndexProses" asp-antiforgery="false" method="get"> <div class="form-actions no-color"> <h4>Search By</h4> <div class="box"> <div class="search"> <label asp-for="FirstMidName"></label> <input name="FirstMidName" type="text" value="@ViewData["CurrentFilter"]"/> <br /> <span asp-validation-for="FirstMidName" class="text-danger"></span> </div> <div class="search"> <label asp-for="LastName"></label> <input name="LastName" type="text" value="@ViewData["CurrentFilter2"]"/> <br /> <span asp-validation-for="LastName" class="text-danger"></span> </div> <div class="search"> <label asp-for="EnrollmentDateFrom"></label> <input name="EnrollmentDateFrom" type="date" value="@ViewData["CurrentFilter3"]"/> <br /> <span asp-validation-for="EnrollmentDateFrom" class="text-danger"></span> </div> <div class="search"> <label asp-for="EnrollmentDateUntil"></label> <input name="EnrollmentDateUntil" type="date" value="@ViewData["CurrentFilter4"]"/> <br /> <span asp-validation-for="EnrollmentDateUntil" class="text-danger"></span> </div> <input type="submit" value="Search" class="btn btn-primary" /> </div> </div> </form> <div class="tbl"> <a asp-action="Create" class="btn btn-primary">Create New [+]</a> <a asp-action="Index" class="btn btn-info text-white">Back to List</a> </div> <form asp-action="Index" asp-controller="Students" method="post"> <table class="table table-hover"> <thead> <tr class="table-light"> <th class="table-light"> @Html.ActionLink("First Name", "IndexProses", new { sortOrder = ViewBag.FirstSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil }) </th> <th> @Html.ActionLink("Last Name", "IndexProses", new { sortOrder = ViewBag.NameSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil }) </th> <th> @Html.ActionLink("Enrollment Date", "IndexProses", new { sortOrder = ViewBag.DateSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil }) </th> <th>Opsi</th> </tr> </thead> <tbody class="opsi"> @foreach (var item in Model.StundentList) { <tr> <td> @Html.DisplayFor(modelItem => item.FirstMidName) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.EnrollmentDate) </td> <td> <a class="btn btn-warning text-white" asp-action="Edit" asp-route-id="@item.ID">Edit</a> | <a class="btn btn-info text-white" asp-action="Details" asp-route-id="@item.ID">Details</a> | <a class="btn btn-danger" asp-action="Delete" asp-route-id="@item.ID">Delete</a> </td> </tr> } </tbody> </table> <ul class="pagination"> @for(int i=1; i<=Model.pageCount; i++) { <li class="page-item"> @if(i != Model.currentPageIndex) { <a class="page-link" href="javascript: PagerClick(@i);">@i</a> } else { <a class="page-link">@i</a> } </li> } </ul> <input type="hidden" id="hfCurrentPageIndex" name="currentPageIndex"/> </form> <script type="text/javascript"> function PagerClick(index) { document.getElementById("hfCurrentPageIndex").value=index; document.forms[0].submit(); } </script>
ViewModel代码
public class StudentVM : IValidatableObject { public int currentPageIndex { get; set; } public int pageCount { get; set; } public List<Student> StundentList { get; set; } [Display(Name = "Last Name :")] public string LastName { get; set; } [Display(Name = "First Name :")] public string FirstMidName { get; set; } [DataType(DataType.Date)] [Display(Name = "Date From :")] public DateTime? EnrollmentDateFrom { get; set; } [DataType(DataType.Date)] [Display(Name = "Until :")] public DateTime? EnrollmentDateUntil { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (FirstMidName == null) { yield return new ValidationResult("input first name!", new[] { "FirstMidName" }); } if (LastName == null) { yield return new ValidationResult("input last name!", new[] { "LastName" }); } if (EnrollmentDateFrom == null) { yield return new ValidationResult("input date from!", new[] { "EnrollmentDateFrom" }); } if (EnrollmentDateUntil == null) { yield return new ValidationResult("input date until!", new[] { "EnrollmentDateUntil" }); } } }
修复方案
1. 核心问题分析
IndexProses返回视图时未给StudentVM的分页属性(StundentList、pageCount)赋值,导致视图访问Model属性时触发空引用异常。- 分页方法
GetStudentList仅查询原始数据,未应用排序/过滤逻辑,与IndexProses完全脱节。 - 分页用Post提交但未携带排序/过滤参数,切换页面后丢失筛选状态。
2. 具体修复步骤
步骤1:合并控制器逻辑,统一处理所有请求
删除IndexProses和HttpPost Index方法,用单个Index方法整合分页、排序、过滤逻辑:
public async Task<IActionResult> Index(int? currentPageIndex, string sortOrder, StudentVM model) { // 初始化分页索引 int page = currentPageIndex ?? 1; int maxRowsPerPage = 5; // 维护排序参数 ViewData["CurrentSort"] = sortOrder; ViewData["NameSortParm"] = sortOrder == "name" ? "name_desc" : "name"; ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date"; ViewData["FirstSortParm"] = string.IsNullOrEmpty(sortOrder) ? "first_desc" : ""; // 维护过滤参数 ViewData["CurrentFilter"] = model.FirstMidName; ViewData["CurrentFilter2"] = model.LastName; ViewData["CurrentFilter3"] = model.EnrollmentDateFrom; ViewData["CurrentFilter4"] = model.EnrollmentDateUntil; // 基础查询 var studentsQuery = from s in _context.Students select s; // 应用排序 studentsQuery = sortOrder switch { "name" => studentsQuery.OrderBy(s => s.LastName), "name_desc" => studentsQuery.OrderByDescending(s => s.LastName), "first_desc" => studentsQuery.OrderByDescending(s => s.FirstMidName), "Date" => studentsQuery.OrderBy(s => s.EnrollmentDate), "date_desc" => studentsQuery.OrderByDescending(s => s.EnrollmentDate), _ => studentsQuery.OrderBy(s => s.FirstMidName), }; // 应用过滤 if (!string.IsNullOrEmpty(model.LastName)) { studentsQuery = studentsQuery.Where(s => s.LastName.Contains(model.LastName)); } if (!string.IsNullOrEmpty(model.FirstMidName)) { studentsQuery = studentsQuery.Where(s => s.FirstMidName.Contains(model.FirstMidName)); } if (model.EnrollmentDateFrom != null && model.EnrollmentDateUntil != null) { studentsQuery = studentsQuery.Where(s => s.EnrollmentDate >= model.EnrollmentDateFrom && s.EnrollmentDate <= model.EnrollmentDateUntil); } // 分页处理 var totalCount = await studentsQuery.CountAsync(); var studentList = await studentsQuery .Skip((page - 1) * maxRowsPerPage) .Take(maxRowsPerPage) .ToListAsync(); // 组装ViewModel var viewModel = new StudentVM { currentPageIndex = page, pageCount = (int)Math.Ceiling((double)totalCount / maxRowsPerPage), StundentList = studentList, // 保留当前过滤参数 FirstMidName = model.FirstMidName, LastName = model.LastName, EnrollmentDateFrom = model.EnrollmentDateFrom, EnrollmentDateUntil = model.EnrollmentDateUntil }; return View(viewModel); }
步骤2:修改视图,统一用Get提交请求
移除分页的Post表单,改为带参数的Get链接,确保所有操作保留筛选状态:
<!-- 替换原有的Post表单,用Get方式处理分页和排序 --> <div> <table class="table table-hover"> <thead> <tr class="table-light"> <th class="table-light"> @Html.ActionLink("First Name", "Index", new { sortOrder = ViewBag.FirstSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil, currentPageIndex = 1 }) </th> <th> @Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil, currentPageIndex = 1 }) </th> <th> @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, FirstMidName = Model.FirstMidName, LastName = Model.LastName, EnrollmentDateFrom = Model.EnrollmentDateFrom, EnrollmentDateUntil = Model.EnrollmentDateUntil, currentPageIndex = 1 }) </th> <th>Opsi</th> </tr> </thead> <tbody class="opsi"> @foreach (var item in Model.StundentList) { <tr> <td>@Html.DisplayFor(modelItem => item.FirstMidName)</td> <td>@Html.DisplayFor(modelItem => item.LastName)</td> <td>@Html.DisplayFor(modelItem => item.EnrollmentDate)</td> <td> <a class="btn btn-warning text-white" asp-action="Edit" asp-route-id="@item.ID">Edit</a> | <a class="btn btn-info text-white" asp-action="Details" asp-route-id="@item.ID">Details</a> | <a class="btn btn-danger" asp-action="Delete" asp-route-id="@item.ID">Delete</a> </td> </tr> } </tbody> </table> <ul class="pagination"> @for(int i=1; i<=Model.pageCount; i++) { <li class="page-item @(i == Model.currentPageIndex ? "active" : "")"> <a class="page-link" asp-action="Index" asp-route-currentPageIndex="@i" asp-route-sortOrder="@ViewBag.CurrentSort" asp-route-FirstMidName="@Model.FirstMidName" asp-route-LastName="@Model.LastName" asp-route-EnrollmentDateFrom="@Model.EnrollmentDateFrom" asp-route-EnrollmentDateUntil="@Model.EnrollmentDateUntil"> @i </a> </li> } </ul> </div> <!-- 修改搜索表单的action为Index --> <form asp-action="Index" method="get"> <div class="form-actions no-color"> <h4>Search By</h4> <div class="box"> <div class="search"> <label asp-for="FirstMidName"></label> <input name="FirstMidName" type="text" value="@ViewData["CurrentFilter"]"/> <
相关产品推荐
相关产品推荐

