Blazor应用按钮点击后数据未重载及状态更新异常排查
钥匙归还功能问题排查
业务流程
- 用户点击按钮完成钥匙归还
- 点击后页面重定向至当前页,按钮切换为“钥匙已归还”文本
- 系统涉及两张表:
KeysList:存储所有可用钥匙,包含布尔类型状态字段IsReturnedKeyIssues:包含布尔类型状态字段IsReturned
现有问题
KeyIssues表的状态并非总能成功更新,但KeysList表状态始终能正常更新- 用户点击归还按钮后,仪表盘页面无法自动重载更新状态,必须切换到其他页面才能看到更新结果
相关代码
Dashboard页面代码
@*Key issues*@ <div class="card mb-4 shadow-lg p-3 mb-5 bg-white rounded"> <div class="card-header text-center text-warning bg-white border-warning"> <h4 class="">Laatste 5 sleuteluitgite</h4> </div> <div class="card-body"> <div class="row"> <div class="col"> <h4 class="">Datum</h4> </div> <div class="col"> <h4>Aan</h4> </div> <div class="col"> <h4>Sleutel</h4> </div> <div class="col"> <h4>Retour</h4> </div> </div> </div> @foreach (var item in keyIssues) { if (item == null) { <p>Loading..</p> } else { var SelectedId = @keysList.Where(m => m.Id.ToString() == item.KeyId).Select(m => m.Id).FirstOrDefault(); <div class="row"> <div class="col"> @item.DateAdded.ToShortDateString() </div> @if (item.IssuedTo != null) { <div class="col"> @UserList.Where(m=>m.Id.ToString() == @item.IssuedTo).Select(m=>m.FirstName + " " + m.LastName).FirstOrDefault() </div> <div class="col"> @keysList.Where(m=>m.Id.ToString() == item.KeyId).Select(m=>m.KeyNumber + " " + m.KeyName).FirstOrDefault() </div> } else { <div class="col"> @item.FirstName @item.LastName </div> <div class="col"> @keysList.Where(m=>m.Id.ToString() == item.KeyId).Select(m=>m.KeyNumber + " " + m.KeyName).FirstOrDefault() </div> } @if (item.IsReturned == false) { <div class="col mb-2"> <button type="button" class="btn btn-outline-info" id="@item.Id" @onclick=" () => SetItemInactive(SelectedId)">Inleveren</button> </div> } else { <div class="col"> <p class="text-success">Retour</p> </div> } <hr> </div> } } </div> async Task SetItemInactive(string id) { var item = keysList.FirstOrDefault(m => m.Id == id); if (item != null) { if (KeyService != null) { await KeyService.SetItemInActive(item.Id); } StateHasChanged(); if (item.IsReturned == true) { NavManager.NavigateTo("/"); } } }
Dashboard的IndexBase代码
using Microsoft.AspNetCore.Components; using Univi.Client.Services.Interface; using Univi.Server.Models; using Univi.Shared; namespace Univi.Client.Pages.Dashboard { public partial class IndexBase : ComponentBase { [Inject] protected IReportService? ReportService { get; set; } [Inject] protected IKeyService? KeyService { get; set; } [Inject] protected IKindofReportService? KindofReportService { get; set; } [Inject] protected IBuildingService? BuildingService { get; set; } [Inject] protected IHandoverService? HandoverService { get; set; } [Inject] protected IMalfunctionService? MalfunctionService { get; set; } [Inject] protected IUserService? UserService { get; set; } protected List<Report> ReportsList = new(); protected List<KeyIssue> keyIssues = new(); protected List<KeyList> keysList = new(); protected List<Building> buildings = new(); protected List<Kindofreport> kindofReports = new(); protected List<Handover> handoverslist = new(); protected List<Malfunction> malfunctionList = new(); protected List<StatusCode> StatuscodeList = new(); protected List<KindofMalfunction> KindofMalfunctionList = new(); protected List<User> UserList = new(); protected override async Task OnInitializedAsync() { if(HandoverService != null) { handoverslist = await HandoverService.GetHandovers(); } if(ReportService != null) { ReportsList = await ReportService.GetLast5Reports(); } if (KeyService != null) { keyIssues = await KeyService.GetKeyIssuesAsync(); keysList = await KeyService.GetKeyListAsync(); } if(BuildingService != null) { buildings = await BuildingService.GetBuildingsAsync(); } if (KindofReportService != null) { kindofReports = await KindofReportService.GetKindsOfReportAsync(); } if(MalfunctionService != null) { malfunctionList = await MalfunctionService.GetMalfunctionsAsync(); StatuscodeList = await MalfunctionService.GetStatusCodesAsync(); } if(UserService != null) { UserList = await UserService.GetUsersAsync(); } } } }
状态修改控制器代码
[HttpPost("inactive")] public async Task<IActionResult> SetItemInactive([FromBody] string id) { //Find the current key and set IsReturned to TRUE var item = await _context.KeysList.FindAsync(id); if (item != null) { var issue = _context.KeyIssues.Where(m => m.KeyId == id).FirstOrDefault(); if (issue != null) { item.IsReturned = true; issue.IsReturned = true; if (issue.IsReturned == true && item.IsReturned == true) { _context.KeyIssues.Update(issue); _context.KeysList.Update(item); await _context.SaveChangesAsync(); return Ok(item); } } } return NoContent(); }
问题分析与修复方案
针对问题1:KeyIssues状态更新不稳定
- 控制器逻辑缺陷:
- 同步查询
FirstOrDefault()在异步方法中可能引发线程问题,需改为异步版本FirstOrDefaultAsync() - 冗余判断
if (issue.IsReturned == true && item.IsReturned == true)完全无效,刚赋值为true无需再判断 - 若同一钥匙存在多条
KeyIssues记录,当前逻辑仅更新第一条,需批量处理所有关联记录
- 同步查询
修复后的控制器代码:
[HttpPost("inactive")] public async Task<IActionResult> SetItemInactive([FromBody] string id) { var item = await _context.KeysList.FindAsync(id); if (item != null) { // 异步查询所有关联的KeyIssues记录 var issues = await _context.KeyIssues.Where(m => m.KeyId == id).ToListAsync(); if (issues.Any()) { item.IsReturned = true; foreach(var issue in issues) { issue.IsReturned = true; } _context.KeysList.Update(item); _context.KeyIssues.UpdateRange(issues); await _context.SaveChangesAsync(); return Ok(item); } } return NoContent(); }
针对问题2:仪表盘页面无法自动更新状态
- 前端数据未刷新:
- 当前仅调用
StateHasChanged(),但本地keyIssues和keysList未从服务器拉取最新数据,重新渲染用的还是旧数据 - 导航到首页时未开启强制重载,Blazor默认会复用现有页面实例
- 当前仅调用
修复后的前端SetItemInactive方法:
async Task SetItemInactive(string id) { if (KeyService != null) { await KeyService.SetItemInActive(id); // 重新获取最新的钥匙和借出记录数据 keyIssues = await KeyService.GetKeyIssuesAsync(); keysList = await KeyService.GetKeyListAsync(); } // 强制重载首页,确保页面完全刷新 NavManager.NavigateTo("/", forceLoad: true); }
- 额外优化:
- 前端循环中
SelectedId的查询完全冗余,item.KeyId本身就是钥匙ID,直接传递给SetItemInactive即可 - 修改按钮点击事件:
@onclick=" () => SetItemInactive(item.KeyId)"
- 前端循环中
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

