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

ASP.NET Core MVC文件上传下载时加载提示及按钮、通知异常解决

问题分析
  1. 按钮状态无法恢复:同步表单提交后,浏览器优先处理文件下载逻辑,原页面的JavaScript代码无法继续执行,导致按钮始终保持禁用状态。
  2. 通知不显示: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:15:13