基于C#与RestSharp的API响应模型结构验证方案咨询
解决RestSharp调用API时的严格DTO契约验证问题
刚好我之前处理过类似的API契约验证需求,结合C#和RestSharp,给你几个实用的方案,按推荐优先级排序:
方案1:使用System.Text.Json的严格反序列化配置(推荐,若项目用.NET Core 3.0+)
这个方案利用System.Text.Json的原生特性,既能强制要求必填字段,又能禁止未知字段,配置简单且无需额外依赖。
步骤1:给DTO添加必填属性
首先给User类的每个字段标记为必填,并指定对应API返回的字段名(如果大小写不一致):
using System.Text.Json.Serialization; public class User { [JsonPropertyName("firstName")] // 匹配API返回的字段名,比如小驼峰 [JsonRequired] public string FirstName { get; set; } [JsonPropertyName("lastName")] [JsonRequired] public string LastName { get; set; } [JsonPropertyName("phoneNumber")] [JsonRequired] public string PhoneNumber { get; set; } }
步骤2:配置RestSharp使用严格的Json序列化器
在初始化RestClient时,指定System.Text.Json的配置,开启DisallowUnknownFields来禁止额外字段:
var client = new RestClient("https://your-company-api.com"); // 配置序列化选项 client.UseSystemTextJson(new JsonSerializerOptions { PropertyNameCaseInsensitive = true, // 如果API字段大小写和DTO不一致,开启这个 DisallowUnknownFields = true // 核心:存在未知字段时抛异常 }); var request = new RestRequest("/api/users/123"); // 添加请求参数(比如认证、路径参数等) try { var user = await client.GetAsync<User>(request); // 到这里说明反序列化成功,完全符合契约要求 } catch (JsonException ex) { // 捕获两种异常情况:缺少必填字段 / 存在未知字段 Console.WriteLine($"API响应不符合契约:{ex.Message}"); // 这里可以做日志记录、告警等处理 }
优点:原生支持,无额外依赖,异常信息清晰直接,代码简洁。
方案2:使用Newtonsoft.Json(Json.NET)的严格配置(若项目已依赖Newtonsoft)
如果你的项目原本就用Newtonsoft.Json,也可以用它的配置实现同样的效果。
步骤1:给DTO添加必填属性
using Newtonsoft.Json; public class User { [JsonProperty("firstName", Required = Required.Always)] public string FirstName { get; set; } [JsonProperty("lastName", Required = Required.Always)] public string LastName { get; set; } [JsonProperty("phoneNumber", Required = Required.Always)] public string PhoneNumber { get; set; } }
步骤2:配置RestSharp的Newtonsoft序列化器
var client = new RestClient("https://your-company-api.com"); client.UseNewtonsoftJson(new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error, // 遇到未知字段时抛异常 PropertyNameCaseInsensitive = true // 可选,适配大小写不一致的场景 }); var request = new RestRequest("/api/users/123"); try { var user = await client.GetAsync<User>(request); } catch (JsonSerializationException ex) { Console.WriteLine($"契约验证失败:{ex.Message}"); }
优点:无缝衔接已有Newtonsoft的项目,配置同样简单。
方案3:手动解析JSON验证(适合自定义复杂逻辑)
如果需要更灵活的验证逻辑(比如一次性收集所有错误,而不是遇到第一个就停止),可以手动解析原始JSON响应进行验证。
示例(用System.Text.Json):
var client = new RestClient("https://your-company-api.com"); var request = new RestRequest("/api/users/123"); var response = await client.GetAsync(request); // 获取原始JSON内容 var rawJson = response.Content; using var jsonDoc = JsonDocument.Parse(rawJson); var rootElement = jsonDoc.RootElement; // 定义需要验证的字段列表(对应API返回的字段名) var expectedFields = new HashSet<string> { "firstName", "lastName", "phoneNumber" }; var validationErrors = new List<string>(); // 检查必填字段是否存在 foreach (var field in expectedFields) { if (!rootElement.TryGetProperty(field, out _)) { validationErrors.Add($"缺少必填字段:{field}"); } } // 检查是否存在额外字段 var actualFields = rootElement.EnumerateObject().Select(p => p.Name).ToList(); var extraFields = actualFields.Except(expectedFields).ToList(); if (extraFields.Any()) { validationErrors.Add($"存在未定义的额外字段:{string.Join(", ", extraFields)}"); } // 处理验证结果 if (validationErrors.Any()) { var errorMsg = string.Join(Environment.NewLine, validationErrors); throw new InvalidOperationException($"API响应契约验证失败:{Environment.NewLine}{errorMsg}"); } // 验证通过后再反序列化为DTO var user = JsonSerializer.Deserialize<User>(rawJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
优点:完全自定义验证逻辑,可批量收集所有错误;缺点:代码量较多,不如自动反序列化简洁。
内容的提问来源于stack exchange,提问作者JumpIntoTheWater




