ASP.NET Core MVC文件上传下载时加载提示及按钮、通知异常解决
问题分析
- 按钮状态无法恢复:同步表单提交后,浏览器优先处理文件下载逻辑,原页面的JavaScript代码无法继续执行,导致按钮始终保持禁用状态。
- 通知不显示:
INotifyService通常依赖TempData存储通知信息,但返回FileResult时页面不会刷新,TempData中的通知无法被页面渲染,只有刷新页面后才会显示。
解决方案
1. 修改前端代码(异步提交表单)
将同步提交改为AJAX异步提交,这样能在请求完成后手动恢复按钮状态,并直接触发通知显示:
<form method="post" enctype="multipart/form-data" id="excelForm"> <div class="row"> <div class="col-sm-8"> <div class="custom-file"> <input type="file" name="file" class="custom-file-input" id="customFile" /> <label class="custom-file-label" for="customFile">select file</label> </div> </div> <div class="col-sm-3 right"> <input type="submit" id="btnSubmit" class="btn btn-primary" value="Upload" /> </div> </div> </form> <script type="text/javascript"> document.getElementById('excelForm').addEventListener('submit', async function(e) { e.preventDefault(); // 阻止默认同步提交 const btnSubmit = document.getElementById('btnSubmit'); btnSubmit.disabled = true; btnSubmit.value = "loading...."; const formData = new FormData(this); formData.append('requestID', '@Model.Id'); // 附加路由参数 try { const response = await fetch('@Url.Action("ExcelFileReader", "Files")', { method: 'POST', body: formData }); if (response.ok) { // 处理文件下载 const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); // 从响应头获取文件名 const fileName = response.headers.get('Content-Disposition').split('filename=')[1].replace(/"/g, ''); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); // 显示成功通知,替换为你项目中的通知组件调用 alert(' successfully added'); } else { alert('处理失败,请重试'); } } catch (error) { console.error(error); alert('请求出错,请重试'); } finally { // 恢复按钮状态 btnSubmit.disabled = false; btnSubmit.value = "Upload"; } }); </script>
2. 修改控制器代码
调整响应头确保文件名正确传递,同时移除依赖TempData的通知逻辑(改为前端处理):
[HttpPost] public async Task<IActionResult> ExcelFileReader(IFormFile file, Guid requestID) { CurrentUser currentUser = _currentUserService.OnlineUser(); System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); var uploadDirectory = $"{Directory.GetCurrentDirectory()}\\wwwroot\\Uploads"; // 确保上传目录存在 if (!Directory.Exists(uploadDirectory)) { Directory.CreateDirectory(uploadDirectory); } var fileNameWithDate = $"{currentUser.CompanyName}_{DateTime.Now:yyyyMMdd_HHmmss}_{file.FileName}"; var filePath = Path.Combine(uploadDirectory, fileNameWithDate); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } byte[] byteArray; var outputFileName = $"Failed{file.FileName}.xls"; using (var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read)) { using (var reader = ExcelReaderFactory.CreateReader(stream)) { var workbook = new NPOI.XSSF.UserModel.XSSFWorkbook(); var sheet = workbook.CreateSheet("Worksheet1"); var headerRow = sheet.CreateRow(0); headerRow.CreateCell(0).SetCellValue("PozNo"); headerRow.CreateCell(1).SetCellValue("Leng"); headerRow.CreateCell(2).SetCellValue("Count"); headerRow.CreateCell(3).SetCellValue("Failed Reason"); // 这里补充读取Excel数据并填充到sheet的逻辑(原代码未实现) using (var memoryStream = new MemoryStream()) { workbook.Write(memoryStream); byteArray = memoryStream.ToArray(); } } } // 设置响应头,指定下载文件名 var contentDisposition = new System.Net.Mime.ContentDisposition { FileName = outputFileName, Inline = false }; Response.Headers.Add("Content-Disposition", contentDisposition.ToString()); return File(byteArray, "application/vnd.ms-excel"); }
补充说明
- 如果项目中有统一的UI通知组件(如Toast提示),可将前端代码中的
alert(' successfully added')替换为对应组件的调用(例如notify.success(' successfully added'))。 - 若仍希望后端控制通知内容,可修改控制器返回JSON格式数据,包含文件的Base64字符串和通知文本,前端解析后处理下载并显示通知。
内容的提问来源于stack exchange,提问作者Mr.F.K
相关产品推荐
相关产品推荐

