.NET 7 WPF应用调用Microsoft Graph上传OneDrive时出现ODataError
解决WPF中使用Microsoft Graph API上传OneDrive文件的ODataError问题
可能的问题及修复步骤
1. 租户ID拼写错误
你的代码中tenantId变量值包含空格("Tena ntId"),这会导致认证请求的Authority地址无效,获取的令牌可能无法正确访问OneDrive。修复:替换为无空格的正确租户ID。
2. 自定义认证提供者冗余且存在兼容性风险
自定义CustomAuthenticationProvider手动处理请求头,不符合Microsoft Graph SDK v5+的官方推荐方式,容易出现权限传递错误。
修复:
移除自定义CustomAuthenticationProvider类,使用Azure.Core.AccessTokenCredential初始化GraphServiceClient,代码更简洁且可靠:
// 替换原有的graphClient初始化代码 var credential = new AccessTokenCredential(result.AccessToken); graphClient = new GraphServiceClient(credential);
需要添加命名空间:using Azure.Core;
3. 冗余的Drive请求
你先调用graphClient.Me.Drive.GetAsync()获取Drive ID,再通过graphClient.Drives[myDrive.Id]访问,多了一次不必要的API请求。可以直接访问当前用户的Drive根目录。
修复:
将上传会话的请求代码简化为:
var uploadSession = await graphClient.Me.Drive.Root .ItemWithPath(Path.GetFileName(filePath)) .CreateUploadSession .PostAsync(uploadSessionRequestBody);
4. 不完整的异常信息捕获
当前捕获ODataError时仅打印基础消息,无法获取错误代码和详细信息,难以定位具体问题(如权限不足、路径非法等)。
修复:
完善异常处理逻辑,打印完整错误信息:
catch (ODataError ex) { var errorDetails = ex.Error.Details != null ? string.Join("\n", ex.Error.Details.Select(d => $"{d.Code}: {d.Message}")) : "无详细信息"; MessageBox.Show($"上传失败:\n错误代码: {ex.Error.Code}\n消息: {ex.Error.Message}\n详细信息: {errorDetails}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); }
修正后的完整代码
using Microsoft.Graph; using Microsoft.Graph.Models; using Microsoft.Graph.Models.ODataErrors; using Microsoft.Identity.Client; using Azure.Core; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; using Microsoft.Win32; namespace WpfApp1 { public partial class MainWindow : Window { private GraphServiceClient graphClient; private bool IsAuthenticated => graphClient != null; public MainWindow() { InitializeComponent(); } private async void Window_Loaded(object sender, RoutedEventArgs e) { await Authenticate(); } private async Task Authenticate() { var clientId = "你的ClientId"; var redirectUri = "https://localhost/"; var scopes = new[] { "User.Read", "Files.ReadWrite.All", "offline_access" }; var tenantId = "你的正确TenantId"; // 修复:替换为无空格的正确租户ID IPublicClientApplication app = PublicClientApplicationBuilder .Create(clientId) .WithRedirectUri(redirectUri) .WithTenantId(tenantId) // 提前设置租户ID,避免后续重复指定 .Build(); var accounts = await app.GetAccountsAsync(); AuthenticationResult result; try { result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) .ExecuteAsync(); } catch (MsalUiRequiredException) { result = await app.AcquireTokenInteractive(scopes) .WithPrompt(Prompt.SelectAccount) .ExecuteAsync(); } // 使用官方推荐的TokenCredential初始化GraphServiceClient var credential = new AccessTokenCredential(result.AccessToken); graphClient = new GraphServiceClient(credential); } private async void btnSelectFile_Click(object sender, RoutedEventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); if (openFileDialog.ShowDialog() == true) { string filePath = openFileDialog.FileName; await UploadFile(filePath); } } private async Task UploadFile(string filePath) { if (!IsAuthenticated) { MessageBox.Show("请先完成认证。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (!File.Exists(filePath)) { MessageBox.Show("所选文件不存在。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); return; } try { var uploadSessionRequestBody = new Drives.Item.Items.Item.CreateUploadSession.CreateUploadSessionPostRequestBody { Item = new DriveItemUploadableProperties { AdditionalData = new Dictionary<string, object> { { "@microsoft.graph.conflictBehavior", "replace" }, }, }, }; // 简化Drive访问路径,直接使用当前用户的根目录 var uploadSession = await graphClient.Me.Drive.Root .ItemWithPath(Path.GetFileName(filePath)) .CreateUploadSession .PostAsync(uploadSessionRequestBody); int maxSliceSize = 320 * 1024; using (var fileStream = File.OpenRead(filePath)) { var fileUploadTask = new LargeFileUploadTask<DriveItem>( uploadSession, fileStream, maxSliceSize); var totalLength = fileStream.Length; IProgress<long> progress = new Progress<long>(prog => { Console.WriteLine($"已上传 {prog} / {totalLength} 字节"); }); var uploadResult = await fileUploadTask.UploadAsync(progress); if (uploadResult.UploadSucceeded) { MessageBox.Show($"上传完成,文件ID: {uploadResult.ItemResponse.Id}", "成功", MessageBoxButton.OK, MessageBoxImage.Information); } else { MessageBox.Show("上传失败", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } } catch (ODataError ex) { var errorDetails = ex.Error.Details != null ? string.Join("\n", ex.Error.Details.Select(d => $"{d.Code}: {d.Message}")) : "无详细信息"; MessageBox.Show($"上传失败:\n错误代码: {ex.Error.Code}\n消息: {ex.Error.Message}\n详细信息: {errorDetails}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception ex) { MessageBox.Show($"上传出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } } }
额外检查项
- 确保Azure AD应用注册中已添加
Files.ReadWrite.All权限,并已授予管理员同意(如果是租户范围内的应用)。 - 确认本地文件路径无特殊字符,OneDrive文件名符合命名规范。
内容的提问来源于stack exchange,提问作者Deepak Choudhary
相关产品推荐
相关产品推荐

