ASP.NET Core MVC中使用jQuery.ajax传递模型与额外参数至控制器的绑定问题
我看了你的代码,发现几个关键问题导致参数没有正确绑定,咱们一步步来解决:
一、先修正JavaScript里的两个小错误
1. updateModel函数没有返回模型
你的updateModel函数里填充了全局的model变量,但函数本身没有返回值,执行model = updateModel()后,model会变成undefined,这直接导致请求数据是空的!
修正这个函数,最后加上return model;:
var model = {}; //global variable function updateModel() { for(const element of document.querySelectorAll("input.account-property-input")) { if(element instanceof HTMLInputElement && typeof element.name === "string" && element.name.trim().length > 0) { model[element.name] = element.value; } } let checkbox = document.querySelector("input#enable-two-factor-checkbox"); if(checkbox instanceof HTMLInputElement) { model[checkbox.name] = checkbox.checked; } if(checkbox.checked) { radio = document.querySelector("input#two-factor-by-phone-radio"); model.TwoFactorMethod = radio.checked ? "TwoFactorByPhoneNumber" : "TwoFactorByEmail"; } // 新增:返回填充好的模型 return model; }
2. 修正Ajax请求的数据格式
你设置了contentType: "application/json; charset=utf-8",但直接传递了JavaScript对象{ model: model, contactType: contactType },jQuery默认会把对象编码成form-urlencoded格式,和你指定的contentType不匹配,导致后端无法解析JSON数据。
需要用JSON.stringify()把数据转成JSON字符串:
model = updateModel(); const urlAction = window.location.origin + "/UserAccount/ConfirmContact"; const jqXHR = $.ajax({ method: "POST", url: urlAction, // 把对象序列化为JSON字符串 data: JSON.stringify({ model: model, contactType: contactType }), contentType: "application/json; charset=utf-8" }); await jqXHR?.then( async function(data, textStatus, jqxhr) { alert(`request to ${urlAction} is successed`); }, function(jqxhr, textStatus, errorThrown) { alert(`request to ${urlAction} is failed; status: ${textStatus}; error: ${errorThrown}`); });
二、修正控制器的参数绑定逻辑
ASP.NET Core中,[FromBody]特性只能用于一个参数(因为请求体只能读取一次),所以直接写两个参数AccountViewModel model, ContactType contactType的话,后端无法同时从JSON请求体中绑定两个参数。这里有两种解决方案:
方案一:创建一个包装类(推荐)
新建一个DTO类,把需要传递的模型和额外参数包装在一起:
public class ConfirmContactRequest { public AccountViewModel Model { get; set; } public ContactType ContactType { get; set; } }
然后修改控制器的Action,用这个DTO作为参数,并加上[FromBody]特性:
[HttpPost] public async Task<IActionResult> ConfirmContact([FromBody] ConfirmContactRequest request) { if(request?.Model != null) { if(request.ContactType == ContactType.PhoneNumber) { if(await PhoneConfirmationService.SendVerificationCode(request.Model)) { request.Model.PhoneConfirmationState = ContactConfirmationState.AwaitingConfirmation; } } else { if(await EmailConfirmationService.SendVerificationCode(HttpContext, request.Model)) { request.Model.EmailConfirmationState = ContactConfirmationState.AwaitingConfirmation; } } } return View("Register", request?.Model ?? new AccountViewModel()); }
方案二:将额外参数放在URL查询字符串中
如果不想创建新的类,可以把contactType作为URL的查询参数传递,模型从请求体绑定:
修改JavaScript的URL拼接:
// 把contactType拼到URL的查询参数里 const urlAction = `${window.location.origin}/UserAccount/ConfirmContact?contactType=${contactType}`; const jqXHR = $.ajax({ method: "POST", url: urlAction, // 只传递model对象,不需要包装 data: JSON.stringify(model), contentType: "application/json; charset=utf-8" });
然后修改控制器的Action,给contactType加上[FromQuery]特性:
[HttpPost] public async Task<IActionResult> ConfirmContact([FromBody] AccountViewModel model, [FromQuery] ContactType contactType) { // 原有逻辑不变 if(model != null) { if(contactType == ContactType.PhoneNumber) { if(await PhoneConfirmationService.SendVerificationCode(model)) { model.PhoneConfirmationState = ContactConfirmationState.AwaitingConfirmation; } } else { if(await EmailConfirmationService.SendVerificationCode(HttpContext, model)) { model.EmailConfirmationState = ContactConfirmationState.AwaitingConfirmation; } } } return View("Register", model ?? new AccountViewModel()); }
最后验证一下
做完这些修改后,再测试请求:
- 确保
updateModel正确返回填充后的模型 - 请求数据是正确的JSON格式
- 控制器参数能正确绑定到传递的数据
这样应该就能解决参数没有初始化的问题了。
内容来源于stack exchange

