如何用C#反序列化Web API返回的BadRequest错误响应?
解决Web API错误JSON反序列化的问题
我帮你搞定这个棘手的反序列化问题!这种带特殊空键的ModelState结构确实容易踩坑,咱们一步步拆解解决。
首先,先明确你收到的错误JSON的特殊之处:ModelState里有一个空字符串作为键,对应的值是包含具体错误信息的数组。先把这个JSON结构再理清楚:
{ "$id":"1", "Message":"The request is invalid.", "ModelState": { "$id":"2", "": { "$id":"3", "$values": ["Name username@gmail.com is already taken."] } } }
下面给你两种可行的解决方案,按需选择:
方案一:强类型类(推荐,类型安全)
创建对应JSON结构的实体类,关键是用JsonProperty特性指定空字符串的键,让序列化器能正确匹配:
using Newtonsoft.Json; using System.Collections.Generic; // 顶层错误响应类 public class ApiErrorResponse { [JsonProperty("$id")] public string Id { get; set; } public string Message { get; set; } // 用字典接收ModelState的所有键值对,包括空字符串键 public Dictionary<string, ModelStateError> ModelState { get; set; } } // ModelState中每个键对应的错误结构 public class ModelStateError { [JsonProperty("$id")] public string Id { get; set; } [JsonProperty("$values")] public List<string> ErrorMessages { get; set; } }
然后反序列化并提取错误信息:
// 假设responseString是你从API获取到的JSON字符串 var errorResponse = JsonConvert.DeserializeObject<ApiErrorResponse>(responseString); // 提取空键对应的错误信息(这里用FirstOrDefault避免空引用) var specificError = errorResponse.ModelState[""]?.ErrorMessages?.FirstOrDefault(); // 现在specificError就是"Name username@gmail.com is already taken." // 可以直接展示给用户
这种方式的好处是类型安全,后续如果API返回的结构有变化,编译器能帮你提前发现问题。
方案二:动态类型(快速验证)
如果只是临时调试或者不想创建实体类,可以用动态类型快速提取错误:
using Newtonsoft.Json; var dynamicError = JsonConvert.DeserializeObject<dynamic>(responseString); var errorMessage = dynamicError.ModelState[""].$values[0].ToString();
这种方式简单直接,但没有类型检查,适合快速验证场景。
注意事项(针对System.Text.Json用户)
如果你用的是.NET Core/.NET 5+自带的System.Text.Json,需要注意配置序列化选项,确保能正确处理空键和大小写:
using System.Text.Json; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, // 忽略大小写匹配 AllowTrailingCommas = true // 可选,防止JSON有多余逗号 }; var errorResponse = JsonSerializer.Deserialize<ApiErrorResponse>(responseString, options); var specificError = errorResponse.ModelState[""]?.ErrorMessages?.FirstOrDefault();
这样就能完美解决你遇到的反序列化问题啦!
内容的提问来源于stack exchange,提问作者Amokachi
相关产品推荐
相关产品推荐

