ASP.NET通过AJAX传文件到控制器时附件为null的解决方法
问题根因
你现在的代码有3个核心问题导致文件和数据接收失败:
- 错误将FormData对象放入JSON中做序列化,JSON格式无法承载二进制文件数据,同时手动指定
contentType: 'application/json',让请求以JSON格式发送,完全丢失了multipart格式的文件段,后端自然读不到Request.Files - 模型中ATTACHMENT字段定义为string类型,根本无法接收二进制文件对象
- ajax未配置
processData: false,jQuery会默认将传入的FormData对象转成查询字符串,直接破坏文件结构;同时FormData内的字段名和后端模型的属性、参数结构不匹配,模型绑定无法正常映射字段
修复步骤
1. 调整模型类的文件字段类型
文件不能用string类型接收,需要根据你用的MVC版本替换成对应文件类型:
- 如果是.NET Framework 版本的ASP.NET MVC 5:
public class SnapShotReceivedData { public string REASON { get; set; } public string COMMENT { get; set; } public HttpPostedFileBase ATTACHMENT { get; set; } // 多文件上传就改成 public List<HttpPostedFileBase> ATTACHMENT { get; set; } }
- 如果是ASP.NET Core MVC:
public class SnapShotReceivedData { public string REASON { get; set; } public string COMMENT { get; set; } public IFormFile ATTACHMENT { get; set; } // 多文件上传就改成 public List<IFormFile> ATTACHMENT { get; set; } }
2. 重写前端提交逻辑
核心要求:不要做JSON序列化,不要手动设置Content-Type,所有普通字段和文件都追加到同一个FormData实例中,修正后的代码如下:
function submit() { var REASON_EXEMPT= $('#reasonexe').val(); var COMMENT_EXEMPT= $('#txtCommentexe').val(); var $file = document.getElementById('file'); var $formData = new FormData(); // 追加普通字段,键名必须和后端参数、模型属性结构完全匹配 // 如果控制器参数改成单个对象而非List,直接去掉sObject[0].前缀即可 $formData.append("sObject[0].REASON", REASON_EXEMPT); $formData.append("sObject[0].COMMENT", COMMENT_EXEMPT); // 追加文件 if ($file.files.length > 0) { // 单文件直接追加 $formData.append("sObject[0].ATTACHMENT", $file.files[0]); // 多文件就循环追加到同一个键名 // for (var i = 0; i < $file.files.length; i++) { // $formData.append("sObject[0].ATTACHMENT", $file.files[i]); // } } $.ajax({ contentType: false, // 让浏览器自动生成multipart/form-data请求头和正确的分隔符 processData: false, // 禁止jQuery转码FormData对象 dataType: 'json', type: 'POST', url: '@Url.Action("SetHCMNIDSnapData", "Home")', data: $formData, success: function (result) { if (result=='10') { // 对应业务逻辑 } if (result == '12') { // 对应业务逻辑 } }, error: function (response) { // 错误处理逻辑 } }); }
如果你不需要提交多条数据,只传单条记录,可以直接把控制器参数改成
SnapShotReceivedData sObject,前端FormData追加字段时直接用REASON/COMMENT/ATTACHMENT作为键名即可,不需要加sObject[0].前缀。
3. 修正控制器动作方法
给方法加POST请求标记,不需要手动读取Request.Files,模型绑定会自动映射文件到属性:
- .NET Framework MVC 版本:
[HttpPost] public JsonResult SetHCMNIDSnapData(List<SnapShotReceivedData> sObject) { if (sObject != null && sObject.Count > 0 && sObject[0].ATTACHMENT != null) { // 直接取文件属性即可 string fileName = sObject[0].ATTACHMENT.FileName; int fileSize = sObject[0].ATTACHMENT.ContentLength; // 自定义文件保存逻辑 } // 你的业务逻辑 return Json(10); }
- ASP.NET Core 版本,需要给参数加[FromForm]标记明确绑定来源:
[HttpPost] public JsonResult SetHCMNIDSnapData([FromForm]List<SnapShotReceivedData> sObject) { // 逻辑和上述一致,直接从sObject[0].ATTACHMENT取文件即可 }
关键注意点
- 所有带文件上传的POST请求,必须使用
multipart/form-data编码,不能用application/json,JSON格式本身不支持二进制内容传输 - 用jQuery+FormData传文件时,必须设置
processData:false和contentType:false,否则请求会被错误转码导致文件丢失 - FormData中追加的字段名必须和后端模型的属性名、参数层级完全匹配,传集合类型时需要带
[索引]前缀才能被模型绑定正确识别
内容的提问来源于stack exchange,提问作者hotflix
相关产品推荐
相关产品推荐

