C# API Post接收JSON:本地正常远程FromBody为null问题排查
解决ASP.NET Web API接收非标准多行JSON(application/json类型)的问题
我一眼就看出问题出在哪了——当请求Content-Type切换成application/json时,ASP.NET Web API的默认模型绑定逻辑和text/plain完全不一样,直接导致你的_inputJson变成了null,触发了204的返回。
问题根源拆解
- 用
text/plain时,Web API会把请求体的原始内容直接塞给[FromBody] string,所以你的processJson按换行拆分的逻辑能正常工作。 - 但换成
application/json后,Web API会自动尝试把请求体解析成标准JSON对象,而你的输入是每行一个独立JSON、没有数组包裹的非标准格式,解析直接失败,_inputJson就成了null,刚好命中你判断null返回204的分支。
解决方案
这里给你几个可行的处理方案,按需选择:
方案1:直接读取请求流的原始内容(最稳妥)
放弃依赖[FromBody] string的模型绑定,直接从请求流里读取完整的原始字符串,不管Content-Type是什么都能拿到正确内容。修改你的Post方法:
public async Task<HttpResponseMessage> PostString() { string _inputJson; // 直接读取请求流的原始内容 using (var reader = new StreamReader(await Request.Content.ReadAsStreamAsync())) { _inputJson = await reader.ReadToEndAsync(); } if (string.IsNullOrEmpty(_inputJson)) { return Request.CreateErrorResponse(HttpStatusCode.NoContent, "The Json was null"); } else { try { var arrJson = processJson(_inputJson); using (ModelEntities entities = new ModelEntities()) { for (int i = 0; i < arrJson.Count; i++) { var jTest = JsonConvert.DeserializeObject<TestClass>(arrJson[i].ToString()); var userRoles = jTest.RolesClass; var userId = jTest.Id; entities.User.Add(jTest); foreach (var _role in userRoles) { if (_role != null) { _role.id = userId; entities.userRoles.Add(_role); } } } // 建议统一保存,不要循环里多次Save,性能会差很多 entities.SaveChanges(); } return Request.CreateResponse(HttpStatusCode.OK); } catch (Exception ex) { return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.Message.ToString()); } } }
方案2:优化processJson的拆分逻辑
你的拆分只处理了\n,但实际请求里可能存在Windows风格的\r\n或者空行,会导致拆分出无效的空字符串,后续反序列化报错。优化一下方法:
public List<string> processJson(string strInput) { // 同时处理两种换行符,过滤掉空行 return strInput.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries) .Where(line => !string.IsNullOrWhiteSpace(line)) .ToList(); }
方案3:让发送方改成标准JSON数组(最优解)
如果远程服务器可以调整,建议让对方把请求体改成标准的JSON数组格式:
[ {"id": "1","name": "Cindy","role": [{"name": "HR"}]}, {"id": "2","name": "Frank","role": [{"name": "Admin"}]}, {"id": "3","name": "John","role": [{"name": "Admin"},{"name": "HR"}]} ]
这样你可以直接用[FromBody] List<TestClass> _inputList接收,不需要自己拆分和反序列化,代码会简洁很多,也符合JSON规范。
额外建议
- 尽量不要在循环里频繁调用
SaveChanges(),这会多次触发数据库操作,严重影响性能,统一在循环结束后保存一次就好。 - 可以加个日志记录,比如读取到
_inputJson后把内容打出来,方便后续排查类似问题。
内容的提问来源于stack exchange,提问作者deepfriedprune
相关产品推荐
相关产品推荐

