RestSharp升级后无法反序列化JIRA API返回JSON的问题排查
问题:RestSharp升级后反序列化JIRA API返回数据失败
场景复现
通过RestSharp调用JIRA API获取用户组成员列表,旧版本RestSharp可正常运行,升级至最新版本后抛出反序列化错误。
调用代码
options.Authenticator = new HttpBasicAuthenticator(_jiraConfig.UserName, _jiraConfig.Token); options.BaseUrl = new Uri(_jiraConfig.Url); _restClient = new RestClient(options); var request = new RestRequest($"rest/api/2/group/member?groupname={_jiraConfig.GroupName}&includeInactiveUsers=false&startAt={start}&maxResults=100", Method.Get); PagedQueryResult<JiraGroupUser> jiraUsers = await _restClient.GetAsync<PagedQueryResult<JiraGroupUser>>(request);
JIRA API返回的JSON数据
{ "self": "https://xxx.atlassian.net/rest/api/2/group/member?includeInactiveUsers=false&maxResults=50&groupId=f4a5587d-92ec-4cbf-824e-8489f38d147f&startAt=0", "nextPage": "https://xxx.atlassian.net/rest/api/2/group/member?includeInactiveUsers=false&maxResults=50&groupId=f4a5587d-92ec-4cbf-824e-8489f38d147f&startAt=50", "maxResults": 50, "startAt": 0, "total": 94, "isLast": false, "values": [ { "self": "https://xxx.atlassian.net/rest/api/2/user?accountId=yyy", "accountId": "yyy", "avatarUrls": { "48x48": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/yyy/aaa/48", "24x24": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/yyy/aaa/24", "16x16": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/yyy/aaa/16", "32x32": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/yyy/aaa/32" }, "displayName": "ABC", "active": true, "timeZone": "Europe/Zurich", "accountType": "atlassian" }, { "self": "https://xxx.atlassian.net/rest/api/2/user?accountId=zzz", "accountId": "zzz", "avatarUrls": { "48x48": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/zzz/bbb/48", "24x24": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/zzz/bbb/24", "16x16": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/zzz/bbb/16", "32x32": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/zzz/bbb/32" }, "displayName": "DEF", "active": true, "timeZone": "Europe/Zurich", "accountType": "app" } ] }
反序列化模型类
internal class PagedQueryResult<T> : IEnumerable<T> { public List<T> Values { get; set; } = new List<T>(); public int StartAt { get; set; } public int MaxResults { get; set; } public int Total { get; set; } public bool IsLast { get; set; } public string Self { get; set; } public string NextPage { get; set; } public PagedQueryResult() { } public IEnumerator<T> GetEnumerator() { return Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Values.GetEnumerator(); } }
public class JiraGroupUser { public string AccountId { get; set; } public string AccountType { get; set; } public bool Active { get; set; } public string DisplayName { get; set; } public string EmailAddress { get; set; } public string TimeZone { get; set; } public string Self { get; set;} }
错误信息
System.Text.Json.JsonException: 'The JSON value could not be converted to CloudToolsUsersExporter.JiraExporter.Models.PagedQueryResult`1[CloudToolsUsersExporter.JiraExporter.Models.JiraGroupUser]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.'
问题原因
- 序列化器默认行为变更:RestSharp新版本默认使用
System.Text.Json作为序列化器,而旧版本默认使用Newtonsoft.Json。两者核心差异在于:System.Text.Json默认不忽略JSON中未在模型定义的字段,且默认区分属性名大小写;Newtonsoft.Json默认忽略未知字段,且默认不区分大小写。
- 属性名匹配问题:JSON中的字段为驼峰命名(如
maxResults、isLast),而模型类属性为Pascal命名(如MaxResults、IsLast),System.Text.Json默认大小写敏感,会导致字段映射失败。 - 未定义的
avatarUrls字段触发了System.Text.Json的反序列化错误。
解决办法
方法1:配置System.Text.Json适配JIRA JSON格式
在创建RestClient时,配置JsonSerializerOptions,开启大小写不敏感匹配并忽略未知字段:
var options = new RestClientOptions(_jiraConfig.Url) { Authenticator = new HttpBasicAuthenticator(_jiraConfig.UserName, _jiraConfig.Token), JsonSerializerOptions = new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true, // 忽略属性名大小写 IgnoreUnknownFields = true, // 忽略JSON中未定义的字段 PropertyNamingPolicy = JsonNamingPolicy.CamelCase // 自动映射驼峰与Pascal命名 } }; _restClient = new RestClient(options);
方法2:给模型添加特性适配
如果不需要全局配置,可以给模型类/属性添加特性:
- 给
JiraGroupUser添加[JsonExtensionData]捕获未知字段,避免报错:public class JiraGroupUser { public string AccountId { get; set; } public string AccountType { get; set; } public bool Active { get; set; } public string DisplayName { get; set; } public string EmailAddress { get; set; } public string TimeZone { get; set; } public string Self { get; set;} [JsonExtensionData] public Dictionary<string, JsonElement> ExtraFields { get; set; } // 存储avatarUrls等未知字段 } - 给模型属性添加
[JsonPropertyName]明确指定JSON字段名:internal class PagedQueryResult<T> : IEnumerable<T> { [JsonPropertyName("values")] public List<T> Values { get; set; } = new List<T>(); [JsonPropertyName("startAt")] public int StartAt { get; set; } [JsonPropertyName("maxResults")] public int MaxResults { get; set; } // 其他属性同理 }
方法3:切换回Newtonsoft.Json
如果希望保留旧版本的序列化行为,可以安装RestSharp.Serializers.NewtonsoftJson NuGet包,然后配置RestSharp使用Newtonsoft.Json:
var options = new RestClientOptions(_jiraConfig.Url) { Authenticator = new HttpBasicAuthenticator(_jiraConfig.UserName, _jiraConfig.Token) }; _restClient = new RestClient(options) .UseNewtonsoftJson(); // 切换为Newtonsoft.Json序列化器
内容的提问来源于stack exchange,提问作者J4N
相关产品推荐
相关产品推荐

