ASP.NET Core MVC集成测试中Post请求控制器参数接收异常排查
问题原因
ASP.NET Core MVC控制器的Action参数默认采用表单数据绑定,而你的测试代码通过JsonContent.Create发送的是JSON格式的请求体,框架无法自动将JSON内容绑定到未指定绑定源的TestVm参数,导致控制器接收不到数据。直接调用控制器方法时是直接传入对象实例,绕过了HTTP请求的参数绑定流程,所以能正常运行。
解决方案
提供两种可行方案,根据你的业务场景选择:
方案一:修改控制器,指定从请求体绑定JSON
给UpdateAsync方法的TestVm参数添加[FromBody]特性,明确告诉框架从请求体的JSON内容中绑定参数:
public async Task<IActionResult> UpdateAsync([FromBody] TestVm vm) { var dto = mapper.Map<TestDto>(vm); var res = await mediator.Send(new UpdateTestCommand { Dto = dto }); if (res != null && !res.Error && dto.Action == FormSaveActions.SaveAndExit) { res.RedirectControllerRoute = "Tests"; res.RedirectActionRoute = "Index"; } return Json(res); }
注意:
[FromBody]特性要求请求的Content-Type为application/json,你的测试代码中JsonContent.Create会自动设置该请求头,无需额外修改。
方案二:修改测试代码,发送表单格式数据
如果控制器需要兼容传统表单提交场景,不想修改控制器代码,可以在测试中构造表单格式的请求内容,匹配MVC默认的绑定规则:
[Fact] public async Task UpdateTestAsync() { var newNotes = "These notes have now been changed"; var formData = new Dictionary<string, string> { ["Action"] = "Update", ["Id"] = "2", ["CreatedBy"] = "Some guy", ["CreatedDate"] = new DateTime(2023, 08, 02, 14, 30, 05).ToString("o"), ["Closed"] = "false", ["Notes"] = newNotes }; var client = mockWebApp.GetClient(); var content = new FormUrlEncodedContent(formData); var response = await client.PostAsync("/Tests/Update", content); var responseStr = await response.Content.ReadAsStringAsync(); var res = JsonSerializer.Deserialize<RecordResponse>(responseStr); var context = mockWebApp.Context?.Referral; var referral = context?.FirstOrDefault(f => f.Id == 2); response.EnsureSuccessStatusCode(); res.ShouldNotBeNull(); res.Error.ShouldBeFalse(); referral.ShouldNotBeNull(); referral.Notes.ShouldBe(newNotes); }
额外检查点
确保TestVm类满足参数绑定要求:
- 拥有公共的无参构造函数
- 所有需要绑定的属性都有公共的
get和set方法
内容的提问来源于stack exchange,提问作者user10266595
相关产品推荐
相关产品推荐

