使用Fetch将复杂对象从JS传递到MVC控制器失败求助
解决ASP.NET MVC控制器Fetch API参数绑定失败问题
问题场景
现有ASP.NET MVC控制器方法,使用jQuery Ajax调用正常,但改用Fetch API时,控制器始终获取到id=0,Position对象属性全为null。
控制器代码
[HttpPost] public async Task<IActionResult> GetTextFromPos(int id,Position position) { if (position==null || _context.Batches == null) { return NotFound(); } var batchesModel = await _context.Batches .Include(b => b.Profile) .ThenInclude(b => b.Fields) .FirstOrDefaultAsync(m => m.Id == id); batchesModel.OcrData = await _ocrStorageService.LoadOcrDataFromFileSystem(batchesModel.Id); var foundText = "This is found text: "+batchesModel.GetTextFromPosition(position); return Json(foundText); }
正常工作的jQuery Ajax代码
async function getTextFromPos(id, left, top, right, bottom) { const reverseScaleFactor = 1 / scale_factor; const reverseLeft = Math.round(left * reverseScaleFactor); const reverseTop = Math.round(top * reverseScaleFactor); const reverseRight = Math.round(right * reverseScaleFactor); const reverseBottom = Math.round(bottom * reverseScaleFactor); var payload = { id: id, position: { left: reverseLeft, top: reverseTop, right: reverseRight, bottom: reverseBottom } }; $.ajax({ url: '/Batches/GetTextFromPos', type: 'POST', data: payload, success: function (response) { console.log('Response: ', response); }, error: function (error) { console.error('Error:', error); } }); }
绑定失败的Fetch API代码
async function getTextFromPos(id, left, top, right, bottom) { const reverseScaleFactor = 1 / scale_factor; const reverseLeft = Math.round(left * reverseScaleFactor); const reverseTop = Math.round(top * reverseScaleFactor); const reverseRight = Math.round(right * reverseScaleFactor); const reverseBottom = Math.round(bottom * reverseScaleFactor); const payload = { id: id, left: reverseLeft, top: reverseTop, right: reverseRight, bottom: reverseBottom }; try { const response = await fetch('/Batches/GetTextFromPos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const responseData = await response.json(); console.log('Response:', responseData); } catch (error) { console.error('Error:', error); } }
问题原因
- Payload结构不匹配:jQuery的payload是嵌套的
position对象,而Fetch的payload是平级的left/top/right/bottom属性,和控制器期望的参数结构不一致。 - ASP.NET MVC绑定规则限制:默认情况下,ASP.NET MVC只能从请求Body中绑定一个复杂类型对象,无法同时绑定多个参数(
int id和Position position),除非明确指定参数的来源。
解决方案
方案一:统一Payload结构并使用ViewModel接收
1. 修改Fetch的Payload结构
将平级属性改为嵌套的position对象,和jQuery保持一致:
async function getTextFromPos(id, left, top, right, bottom) { const reverseScaleFactor = 1 / scale_factor; const reverseLeft = Math.round(left * reverseScaleFactor); const reverseTop = Math.round(top * reverseScaleFactor); const reverseRight = Math.round(right * reverseScaleFactor); const reverseBottom = Math.round(bottom * reverseScaleFactor); const payload = { id: id, position: { left: reverseLeft, top: reverseTop, right: reverseRight, bottom: reverseBottom } }; try { const response = await fetch('/Batches/GetTextFromPos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const responseData = await response.json(); console.log('Response:', responseData); } catch (error) { console.error('Error:', error); } }
2. 创建ViewModel并修改控制器
定义一个包含Id和Position的ViewModel:
public class GetTextFromPosRequest { public int Id { get; set; } public Position Position { get; set; } }
修改控制器方法,用[FromBody]标记ViewModel参数:
[HttpPost] public async Task<IActionResult> GetTextFromPos([FromBody] GetTextFromPosRequest request) { if (request.Position == null || _context.Batches == null) { return NotFound(); } var batchesModel = await _context.Batches .Include(b => b.Profile) .ThenInclude(b => b.Fields) .FirstOrDefaultAsync(m => m.Id == request.Id); batchesModel.OcrData = await _ocrStorageService.LoadOcrDataFromFileSystem(batchesModel.Id); var foundText = "This is found text: " + batchesModel.GetTextFromPosition(request.Position); return Json(foundText); }
方案二:拆分参数来源(Id从URL传递,Position从Body传递)
1. 修改Fetch请求的URL和Payload
将id作为查询参数拼接到URL,Body只传递Position的属性:
async function getTextFromPos(id, left, top, right, bottom) { const reverseScaleFactor = 1 / scale_factor; const reverseLeft = Math.round(left * reverseScaleFactor); const reverseTop = Math.round(top * reverseScaleFactor); const reverseRight = Math.round(right * reverseScaleFactor); const reverseBottom = Math.round(bottom * reverseScaleFactor); const payload = { left: reverseLeft, top: reverseTop, right: reverseRight, bottom: reverseBottom }; try { const response = await fetch(`/Batches/GetTextFromPos?id=${id}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const responseData = await response.json(); console.log('Response:', responseData); } catch (error) { console.error('Error:', error); } }
2. 修改控制器参数标记
给Position参数添加[FromBody],明确从Body绑定:
[HttpPost] public async Task<IActionResult> GetTextFromPos(int id, [FromBody] Position position) { if (position == null || _context.Batches == null) { return NotFound(); } var batchesModel = await _context.Batches .Include(b => b.Profile) .ThenInclude(b => b.Fields) .FirstOrDefaultAsync(m => m.Id == id); batchesModel.OcrData = await _ocrStorageService.LoadOcrDataFromFileSystem(batchesModel.Id); var foundText = "This is found text: " + batchesModel.GetTextFromPosition(position); return Json(foundText); }
内容的提问来源于stack exchange,提问作者Adam Kotvas
相关产品推荐
相关产品推荐

