You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:20:57