MVC Core调用API时响应内容无法反序列化填充User对象故障排查
问题诱因
- 远端API返回结构被包装:你调用的目标API大概率使用了ASP.NET Core内置的
CreatedAtAction/CreatedAtRoute方法返回响应,或是全局配置了响应包装过滤器,实际返回的JSON根节点并未直接暴露User类的字段,而是将User对象嵌套在了value属性中,根节点其余字段均为响应元数据。 - 反序列化目标类型不匹配:你直接将完整响应体反序列化为
User类,ReadFromJsonAsync默认使用的System.Text.Json序列化器无法在根节点找到和User属性匹配的字段,默认会忽略所有未匹配的属性,最终得到的User实例所有属性都会是默认值。
解决方法
你可以根据自己是否能控制目标API的代码,选择以下任意一种方案:
方案一:调整远端API返回格式(可控制目标API时优先选择)
目标API原接口如果用了CreatedAtAction这类带包装的返回写法:public IActionResult PostUser(User user) { // 保存用户逻辑 return CreatedAtAction(nameof(GetUser), new {id = user.Uid}, user); }直接修改为返回纯实体+对应状态码即可:
public IActionResult PostUser(User user) { // 保存用户逻辑 return StatusCode(StatusCodes.Status201Created, user); }修改后API响应体就是纯User结构的JSON,可以直接用
ReadFromJsonAsync<User>()反序列化。方案二:本地新增包装类适配响应结构(无法修改目标API时使用)
先定义泛型响应包装类,匹配当前返回的JSON结构:public class ApiResponseWrapper<T> { public string ActionName { get; set; } public Dictionary<string, object> RouteValues { get; set; } public T Value { get; set; } public int StatusCode { get; set; } }调整反序列化代码,先反序列化到包装类再取出Value属性即可:
var responseWrapper = await response.Content.ReadFromJsonAsync<ApiResponseWrapper<User>>(); User user = responseWrapper.Value;如果是.NET 5以下版本,需要手动传入不区分大小写的序列化配置:
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var responseWrapper = await response.Content.ReadFromJsonAsync<ApiResponseWrapper<User>>(options); User user = responseWrapper.Value;
额外注意事项
你现有代码中先调用ReadFromJsonAsync再调用ReadAsStringAsync的写法存在逻辑问题:HttpContent的内容流是仅向前读取的,第一次读取完成后流位置会移动到末尾,第二次读取会拿到空值。如果你需要同时获取原始响应字符串和反序列化对象,请先读取字符串再手动反序列化:
string responseContent = await response.Content.ReadAsStringAsync(); var responseWrapper = JsonSerializer.Deserialize<ApiResponseWrapper<User>>(responseContent); User user = responseWrapper.Value;
内容的提问来源于stack exchange,提问作者Bleak Morn
相关产品推荐
相关产品推荐

