.NET Core 6 Razor非MVC环境AJAX带进度条文件上传接收问题
.NET Core 6非MVC模式(Razor Pages)AJAX带进度条文件上传后端接收方案
问题背景
使用.NET Core 6非MVC模式(Razor Pages)实现AJAX带进度条文件上传,前端请求已发送文件数据,但后端C#始终接收为null,需将文件转为字节存入数据库,同时保留上传进度显示功能。
前端代码修正
原JavaScript使用FileReader.readAsDataURL将文件转为Base64字符串传递,导致后端无法直接用标准文件接收方式处理。改为使用FormData直接传递文件对象,既符合HTTP文件上传规范,又能保留进度条功能:
HTML代码(无需修改)
<input type="file" id="uploaddoc" style="display: none;" accept=".doc, .docx, .pdf, .png, .jpg, .jpeg" /> <input type="button" value="Browse..." class="btn btn-primary" style="max-width: 150px;" onclick="document.getElementById('uploaddoc').click();" /> <div class="progress" id="progCollapse" style="position: absolute; height: 10px; width: 425px; margin-left: -15px; margin-top: 5px; display: none"> <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" id="progress" style="width: 0" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div></div>
修改后的JavaScript代码
function uploadDoc() { const fileInput = document.getElementById("uploaddoc"); const file = fileInput.files[0]; if (!file) return; // 初始化进度条 $("#progCollapse").show(); document.getElementById("progress").style.width = "0%"; // 创建FormData对象,用于传递文件 const formData = new FormData(); formData.append("doc", file); // "doc"对应后端参数名 formData.append("filename", file.name); // 可选:传递文件名 $.ajax({ xhr: function () { const xhr = new window.XMLHttpRequest(); // 监听上传进度 xhr.upload.addEventListener("progress", function (evt) { if (evt.lengthComputable) { const percentComplete = (evt.loaded / evt.total) * 100; document.getElementById("progress").style.width = percentComplete + "%"; if (percentComplete === 100) { $("#progCollapse").hide(); document.getElementById("progress").style.width = "0%"; } } }, false); return xhr; }, beforeSend: function (xhr) { // 传递防跨站请求伪造令牌 xhr.setRequestHeader("RequestVerificationToken", $('input:hidden[name="__RequestVerificationToken"]').val()); }, type: 'POST', url: "/PageName?handler=SaveFile", contentType: false, // 让浏览器自动设置正确的Content-Type(包含boundary) processData: false, // 禁止jQuery处理FormData data: formData, success: function (response) { // 处理上传成功后的逻辑 console.log("上传成功", response); }, error: function (xhr, status, error) { // 处理错误 console.error("上传失败", error); $("#progCollapse").hide(); document.getElementById("progress").style.width = "0%"; } }); }
后端C#实现(Razor Pages)
在对应的PageModel类中,实现OnPostSaveFile方法,通过IFormFile接收文件,读取为字节数组后存入数据库:
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.IO; public class PageNameModel : PageModel { // 假设你有数据库上下文依赖注入 // private readonly YourDbContext _dbContext; // public PageNameModel(YourDbContext dbContext) // { // _dbContext = dbContext; // } public async Task<IActionResult> OnPostSaveFile(IFormFile doc, string filename) { if (doc == null || doc.Length == 0) { return BadRequest("未接收到有效文件"); } // 将文件转为字节数组 byte[] fileBytes; using (var memoryStream = new MemoryStream()) { await doc.CopyToAsync(memoryStream); fileBytes = memoryStream.ToArray(); } // 这里执行存入数据库的逻辑 // 示例:_dbContext.FileRecords.Add(new FileRecord { Filename = filename, FileData = fileBytes }); // await _dbContext.SaveChangesAsync(); return new JsonResult(new { success = true, message = "文件上传成功" }); } }
关键说明
- 原方案失败原因:原代码将文件转为Base64字符串传递,不符合HTTP标准文件上传格式,导致
IFormFile无法识别。使用FormData直接传递文件对象是标准方式,后端可直接用IFormFile接收。 - 进度条逻辑:
xhr.upload.addEventListener("progress")监听的是文件上传到服务器的进度,这是进度条的正确触发点,无需额外监听xhr本身的progress事件。 - CSRF令牌:Razor Pages默认启用防跨站请求伪造保护,需在AJAX请求头中传递
RequestVerificationToken(对应页面中隐藏的__RequestVerificationToken输入框的值),否则请求会被拒绝。
内容的提问来源于stack exchange,提问作者Stephan Young
相关产品推荐
相关产品推荐

