You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于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

火山引擎 最新活动