调用Microsoft Graph API获取应用列表JSON反序列化失败问题
问题:Microsoft Graph API反序列化JSON报错(旧版本Nuget包限制)
问题描述
调用GET请求获取所有应用的ID和密码过期时间,已经通过Microsoft Graph Explorer验证接口返回正常,但代码在获取HTTP响应后做反序列化时报错。查过同类问题没解决,应该是处理方式漏了关键细节。目前受限于旧版本Graph Nuget包v4.41.0和Core v2.0.13,升级会引发大量破坏性变更,暂时没时间重写全部代码。
错误信息
"Message": "发生错误。", "ExceptionMessage": "无法将当前JSON对象(例如 {\"name\":\"value\"})反序列化为类型'System.Collections.Generic.List`1[Microsoft.Graph.Application]',因为该类型需要JSON数组(例如 [1,2,3])才能正确反序列化。\r\n要解决此错误,请将JSON更改为JSON数组(例如 [1,2,3]),或者更改反序列化类型,使其成为可以从JSON对象反序列化的常规.NET类型(例如不是整数等基元类型,不是数组或List<T>等集合类型)。也可以向该类型添加JsonObjectAttribute以强制其从JSON对象反序列化。\r\n路径 '['@odata.context']', 第1行,位置18。", "ExceptionType": "Newtonsoft.Json.JsonSerializationException", "StackTrace": " at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)\r\n at Newtonsoft.Json.Serialization...
代码实现
public async Task<List<Microsoft.Graph.Application>> GetAppExpList() { List<Microsoft.Graph.Application> apps = null; // 构建请求URL var url = this.GetGraphUrl($"{Consts.GraphUrl}?$select=id,passwordCredentials&$format=json"); // 尝试使用Graph内置方法 List<QueryOption> options = new List<QueryOption> { new QueryOption("$select", "id,DisplayName,passwordCredentials"), new QueryOption("$format", "json") }; // 测试内置方法返回结果,没拿到passwordCredentials var test = await _graphClient.Applications.Request(options).GetAsync(); // 发送GET请求到Graph API var response = await this.HttpHandler.SendGraphGetRequest(url); // 处理响应数据 if (response.IsSuccessStatusCode) { // 获取原始JSON数据(内容是对的) var rawData = await response.Content.ReadAsStringAsync(); // 这里抛出上面的错误 apps = JsonConvert.DeserializeObject<List<Microsoft.Graph.Application>>(rawData); } return apps; }
返回的JSON内容
{ "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#applications(id,passwordCredentials)", "value": [ { "id": "00000000-0000-0000-0000-000000000000", "displayName": "应用1名称", "passwordCredentials": [] }, { "id": "00000000-0000-0000-0000-000000000001", "displayName": "应用2名称", "passwordCredentials": [] }, { "id": "00000000-0000-0000-0000-000000000002", "displayName": "应用3名称", "passwordCredentials": [ { "customKeyIdentifier": null, "displayName": "密钥", "endDateTime": "2025-01-30T14:46:40.985Z", "hint": "oHI", "keyId": "00000000-0000-0000-0000-0000000000", "secretText": null, "startDateTime": "2023-01-31T14:46:40.985Z" } ] } ] }
解决方案
方案1:用包装类反序列化
返回的JSON是包含@odata.context和value数组的对象,不是直接的Application数组,先定义一个包装类:
public class ApplicationResponse { [JsonProperty("@odata.context")] public string ODataContext { get; set; } public List<Microsoft.Graph.Application> Value { get; set; } }
然后修改反序列化代码:
var responseObj = JsonConvert.DeserializeObject<ApplicationResponse>(rawData); apps = responseObj.Value;
方案2:直接提取JSON的value字段
不想创建包装类的话,直接用JObject解析:
var jsonObj = JObject.Parse(rawData); var valueArray = jsonObj["value"]; apps = valueArray.ToObject<List<Microsoft.Graph.Application>>();
额外解决:内置Graph方法拿不到passwordCredentials的问题
旧版本Graph SDK默认不会自动展开passwordCredentials这类导航属性,要加Expand选项:
List<QueryOption> options = new List<QueryOption> { new QueryOption("$select", "id,DisplayName,passwordCredentials"), new QueryOption("$expand", "passwordCredentials") // 新增这行 }; var test = await _graphClient.Applications.Request(options).GetAsync();
这样就能拿到passwordCredentials数据,也可以直接用内置方法替代手动HTTP请求,避免反序列化问题。
内容的提问来源于stack exchange,提问作者whisk
相关产品推荐
相关产品推荐

