C#调用Microsoft Graph无法访问OneDrive/SharePoint站点文档库
问题描述
在Azure AD中注册的Graph API完成认证后,无法访问SharePoint站点文档库及用户OneDrive,使用的是Microsoft Graph SDK 5.6版本。微软文档显示可使用.Me.Drive.Root,但代码中找不到该属性,除直接发送HTTP GET请求外已尝试所有方法,希望避免直接调用HTTP。
以下是可正常运行的代码片段:
using Azure.Core; using Azure.Identity; using Microsoft.Graph; using Microsoft.Graph.Models; using Microsoft.Graph.Me.SendMail; using Microsoft.Graph.Drives.Item.List.Items.Item.DriveItem; namespace GraphApp { class GraphHelper { //Settings object private static Settings? _settings; // User auth token credential private static DeviceCodeCredential? _deviceCodeCredential; // Client configured with user auth private static GraphServiceClient? _userClient; public static void InitializeGraphForUserAuth(Settings settings, Func<DeviceCodeInfo, CancellationToken, Task> deviceCodePrompt) { _settings = settings; var options = new DeviceCodeCredentialOptions { ClientId = settings.ClientId, TenantId = settings.TenantId, DeviceCodeCallback = deviceCodePrompt, }; _deviceCodeCredential = new DeviceCodeCredential(options); _userClient = new GraphServiceClient(_deviceCodeCredential, settings.GraphUserScopes); } public static async Task<string> GetUserTokenAsync() { //Ensure cred isn't null _ = _deviceCodeCredential ?? throw new System.NullReferenceException("Graph has not been initialized for auth"); //Ensure scopes aren't null _ = _settings?.GraphUserScopes ?? throw new System.NullReferenceException("Arugment 'scopes' cannot be null"); // Request token with given scopes var context = new TokenRequestContext(_settings.GraphUserScopes); var response = await _deviceCodeCredential.GetTokenAsync(context); return response.Token; } public static Task<User?> GetUserAsync() { //Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialzed for user auth"); return _userClient.Me.GetAsync((config) => { //Only request specific properties config.QueryParameters.Select = new[] { "displayName", "mail", "userPrincipalName" }; }); } } }
完整的GraphHelper代码:
using Azure.Core; using Azure.Identity; using Microsoft.Graph; using Microsoft.Graph.Models; using Microsoft.Graph.Me.SendMail; using Microsoft.Graph.Drives.Item.List.Items.Item.DriveItem; namespace GraphApp { class GraphHelper { //Settings object private static Settings? _settings; // User auth token credential private static DeviceCodeCredential? _deviceCodeCredential; // Client configured with user auth private static GraphServiceClient? _userClient; public static void InitializeGraphForUserAuth(Settings settings, Func<DeviceCodeInfo, CancellationToken, Task> deviceCodePrompt) { _settings = settings; var options = new DeviceCodeCredentialOptions { ClientId = settings.ClientId, TenantId = settings.TenantId, DeviceCodeCallback = deviceCodePrompt, }; _deviceCodeCredential = new DeviceCodeCredential(options); _userClient = new GraphServiceClient(_deviceCodeCredential, settings.GraphUserScopes); } public static async Task<string> GetUserTokenAsync() { //Ensure cred isn't null _ = _deviceCodeCredential ?? throw new System.NullReferenceException("Graph has not been initialized for auth"); //Ensure scopes aren't null _ = _settings?.GraphUserScopes ?? throw new System.NullReferenceException("Arugment 'scopes' cannot be null"); // Request token with given scopes var context = new TokenRequestContext(_settings.GraphUserScopes); var response = await _deviceCodeCredential.GetTokenAsync(context); return response.Token; } public static Task<User?> GetUserAsync() { //Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialzed for user auth"); return _userClient.Me.GetAsync((config) => { //Only request specific properties config.QueryParameters.Select = new[] { "displayName", "mail", "userPrincipalName" }; }); } public static Task<MessageCollectionResponse?> GetInboxAsync() { //Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); return _userClient.Me //Only messages from Inbox .MailFolders["Inbox"] .Messages .GetAsync((config) => { //Only request specific properties config.QueryParameters.Select = new[] { "from", "isRead", "receivedDateTime", "subject" }; // Get only top 25 results config.QueryParameters.Top = 25; //Sort by received time, newest first config.QueryParameters.Orderby = new[] { "receivedDateTime DESC" }; }); } public static async Task SendMailAsync(string subject, string body, string recipient) { //ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); //Create the message var message = new Message { Subject = subject, Body = new ItemBody { Content = body, ContentType = BodyType.Text }, ToRecipients = new List<Recipient> { new Recipient { EmailAddress = new EmailAddress { Address = recipient } } } }; //Send the message await _userClient.Me .SendMail .PostAsync(new SendMailPostRequestBody { Message = message }); } public static async Task GetSiteDetails(string sitename) //doesn't work { //ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); var result = await _userClient.Sites.GetAsync((requestConfiguration) => { requestConfiguration.QueryParameters.Search = $"{sitename}"; }); } public static async Task GetDrive() { //ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); var childItems = _userClient.Me.Drive. } } }
解决方法
1. 安装缺失的NuGet模块
Microsoft Graph SDK 5.x采用模块化设计,仅安装核心Microsoft.Graph包不足以覆盖所有功能。需手动添加对应模块:
- 安装
Microsoft.Graph.Drives以支持OneDrive相关API - 安装
Microsoft.Graph.Sites以支持SharePoint站点相关API
在NuGet包管理器中执行命令:
Install-Package Microsoft.Graph.Drives Install-Package Microsoft.Graph.Sites
2. 配置正确的权限范围
确保settings.GraphUserScopes包含访问OneDrive和SharePoint所需的权限,示例配置:
var graphUserScopes = new[] { "User.Read", "Mail.Read", "Files.Read", "Sites.Read.All" };
按需选择权限:
- OneDrive:
Files.Read/Files.ReadWrite/Files.Read.All - SharePoint:
Sites.Read.All/Sites.ReadWrite.All
3. 修正代码调用逻辑
SDK 5.x中异步方法必须使用await,且API调用需遵循正确链式结构。修正GetDrive和GetSiteDetails方法:
修正OneDrive调用
public static async Task GetDrive() { _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); // 获取当前用户OneDrive根目录 var driveRoot = await _userClient.Me.Drive.Root.GetAsync(); // 获取根目录下的子文件/文件夹 var childItems = await _userClient.Me.Drive.Root.Children.GetAsync(); }
修正SharePoint站点调用
public static async Task GetSiteDetails(string siteUrl) { _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); // 通过站点URL获取站点实例 var site = await _userClient.Sites.GetByPath(siteUrl, "root").GetAsync(); // 获取站点默认文档库 var siteDrive = await _userClient.Sites[site.Id].Drives.GetAsync(); }
4. 添加必要命名空间
确保代码中引用以下命名空间,以获取完整API提示:
using Microsoft.Graph.Me.Drive; using Microsoft.Graph.Sites;
内容的提问来源于stack exchange,提问作者sibeyzoran
相关产品推荐
相关产品推荐

