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

使用Microsoft Graph SDK与C#获取用户联系人时遇空引用异常

问题描述

我尝试通过Microsoft Graph SDK和C#读取Exchange Online中所有用户的联系人,但执行代码var graphResult = graphClient.Users.Request().GetAsync().Result; Console.WriteLine(graphResult[0].Contacts[0]);时触发NullReferenceException,尽管目标用户实际存在联系人。已在Azure AD中配置相关权限,且通过Graph Explorer登录该用户调用/me/contacts端点能正常获取到3个联系人,怀疑是权限问题但无法定位具体原因,以下是完整代码:

主类代码

using Microsoft.Graph;
using Azure.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using System.Data.SqlClient;

namespace ExchangeTestAppKonsole
{
    internal class Program
    {
        static void Main(string[] args)
        {
            getContacts();
            Console.ReadLine();
        }

        public static void getContacts()
        {
            var clientId = "de196208-b4d7-468f-8fa4-7328551566b9";
            var clientSecret = "~uG8Q~~vrTGuaIPfzeIR9GUUpSK5aaG.KZTYGcnD";
            var redirectUri = "https://global.consent.azure-apim.net/redirect";
            var authority = "https://login.microsoftonline.com/0be300e6-91fd-4638-bcd1-40d742ef6ece/v2.0";
            var cca = ConfidentialClientApplicationBuilder.Create(clientId)
                                                          .WithAuthority(authority)
                                                          .WithRedirectUri(redirectUri)
                                                          .WithClientSecret(clientSecret)
                                                          .Build();

            // use the default permissions assigned from within the Azure AD app registration portal
            List<string> scopes = new List<string>();
            scopes.Add("https://graph.microsoft.com/.default");

            var authenticationProvider = new MsalAuthenticationProvider(cca, scopes.ToArray());
            GraphServiceClient graphClient = new GraphServiceClient(authenticationProvider);

            var graphResult = graphClient.Users.Request().GetAsync().Result;
            Console.WriteLine(graphResult[0].Contacts[0]);
        }
    }
}

认证提供者代码

using Microsoft.Graph;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace ExchangeTestAppKonsole
{
    internal class MsalAuthenticationProvider : IAuthenticationProvider
    {
        private IConfidentialClientApplication _clientApplication;
        private string[] _scopes;

        public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes)
        {
            _clientApplication = clientApplication;
            _scopes = scopes;
        }

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            var token = await GetTokenAsync();
            request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
        }

        public async Task<string> GetTokenAsync()
        {
            AuthenticationResult authResult = null;
            authResult = await _clientApplication.AcquireTokenForClient(_scopes).ExecuteAsync();
            return authResult.AccessToken;
        }
    }
}
解决方案

1. 修复NullReferenceException的核心原因

Graph API默认仅返回用户的基础属性(如ID、DisplayName),不会自动加载Contacts这类嵌套资源,因此graphResult[0].Contacts为null,触发空引用异常。需通过Expand方法显式指定加载嵌套资源,或单独请求单个用户的联系人:

  • 方式1:加载用户时同时扩展联系人(不建议批量操作,性能差)
    var graphResult = graphClient.Users.Request().Expand(u => u.Contacts).GetAsync().Result;
    
  • 方式2:按需加载单个用户的联系人(推荐)
    var users = await graphClient.Users.Request().GetAsync();
    var firstUserContacts = await graphClient.Users[users[0].Id].Contacts.Request().GetAsync();
    Console.WriteLine(firstUserContacts[0].DisplayName);
    

2. 验证权限配置

你使用的是客户端凭据模式(Confidential Client),需确认Azure AD应用注册的权限配置:

  • 必须添加应用权限(而非委托权限):选择Contacts.Read.All
  • 必须点击「授予管理员同意」,应用权限需管理员批准才能生效
  • 注意:Graph Explorer使用的是委托权限(Contacts.Read),仅适用于用户登录场景,与客户端凭据模式不兼容

3. 代码优化建议

  • 避免用.Result阻塞异步方法,改用async/await:
    static async Task Main(string[] args)
    {
        await getContacts();
        Console.ReadLine();
    }
    
    public static async Task getContacts()
    {
        // 省略其他初始化代码
        var users = await graphClient.Users.Request().GetAsync();
        var firstUserContacts = await graphClient.Users[users[0].Id].Contacts.Request().GetAsync();
        Console.WriteLine(firstUserContacts[0].DisplayName);
    }
    
  • 客户端凭据模式无需设置redirectUri,可移除该配置项:
    var cca = ConfidentialClientApplicationBuilder.Create(clientId)
                                                  .WithAuthority(authority)
                                                  .WithClientSecret(clientSecret)
                                                  .Build();
    

内容的提问来源于stack exchange,提问作者flam3shadow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:40:43