使用Graph Api上传大文件到ToDoTask时出现AccessToken为空错误
问题解答
1. 是否允许使用LargeFileUploadTask上传大文件到ToDoTask?
是的,Graph API支持通过LargeFileUploadTask为ToDo任务上传大文件附件。你遇到的错误并非因为不支持该方式,而是初始化LargeFileUploadTask时缺少了关键的认证依赖。
2. 错误原因分析
你当前初始化LargeFileUploadTask的代码只传入了上传会话、文件流和分块大小,但没有传入Graph服务客户端的请求适配器(RequestAdapter)。虽然上传URL本身不需要携带Auth头,但LargeFileUploadTask内部处理分块上传、重试等逻辑时,需要依赖请求适配器获取有效认证令牌,缺少该参数会导致请求时令牌为空,触发InvalidAuthenticationToken错误。
3. 正确实现方式
修改LargeFileUploadTask的初始化代码,补充传入_graphServiceClient.RequestAdapter参数。同时确保你的应用已申请正确的权限(如Tasks.ReadWrite或Tasks.ReadWrite.All)。
修正后的核心代码片段
using (var _stream = new MemoryStream(_attachment.ContentBytes)) { _stream.Position = 0; // 补充传入RequestAdapter参数 LargeFileUploadTask<TaskFileAttachment> _largeFileUploadTask = new LargeFileUploadTask<TaskFileAttachment>(_uploadSession, _graphServiceClient.RequestAdapter, _stream, MaxChunkSize); try { await _largeFileUploadTask.UploadAsync(); } catch (ServiceException errorGraph) { if (errorGraph.StatusCode is HttpStatusCode.InternalServerError or HttpStatusCode.BadGateway or HttpStatusCode.ServiceUnavailable or HttpStatusCode.GatewayTimeout) { await Task.Delay(1000); // 用Task.Delay替代Thread.Sleep,符合异步编程规范 await _largeFileUploadTask.ResumeAsync(); } else throw; } }
完整修正后的方法代码
public async Task CreateTaskBigAttachments(string idList, string title, List<string> categories, BodyType contentType, string content, Importance importance, bool isRemindOn, DateTime? dueTime, cAttachment[] attachments = null) { try { var _newTask = new TodoTask { Title = title, Categories = categories, Body = new ItemBody() { ContentType = contentType, Content = content, }, IsReminderOn = isRemindOn, Importance = importance }; if (dueTime.HasValue) { var _timeZone = TimeZoneInfo.Local; _newTask.DueDateTime = DateTimeTimeZone.FromDateTime(dueTime.Value, _timeZone.StandardName); } var _task = await _graphServiceClient.Me.Todo.Lists[idList].Tasks.Request().AddAsync(_newTask); if (attachments != null && attachments.Length > 0) { foreach (var _attachment in attachments) { var _attachmentContentSize = _attachment.ContentBytes.Length; var _attachmentInfo = new AttachmentInfo { AttachmentType = AttachmentType.File, Name = _attachment.FileName, Size = _attachmentContentSize, ContentType = _attachment.ContentType }; var _uploadSession = await _graphServiceClient.Me .Todo.Lists[idList].Tasks[_task.Id] .Attachments.CreateUploadSession(_attachmentInfo).Request().PostAsync(); using (var _stream = new MemoryStream(_attachment.ContentBytes)) { _stream.Position = 0; // 关键修正:传入RequestAdapter LargeFileUploadTask<TaskFileAttachment> _largeFileUploadTask = new LargeFileUploadTask<TaskFileAttachment>(_uploadSession, _graphServiceClient.RequestAdapter, _stream, MaxChunkSize); try { await _largeFileUploadTask.UploadAsync(); } catch (ServiceException errorGraph) { if (errorGraph.StatusCode is HttpStatusCode.InternalServerError or HttpStatusCode.BadGateway or HttpStatusCode.ServiceUnavailable or HttpStatusCode.GatewayTimeout) { await Task.Delay(1000); await _largeFileUploadTask.ResumeAsync(); } else throw; } } } } } catch (ServiceException errorGraph) { throw; } catch (Exception ex) { throw; } }
额外优化建议
- 用
Task.Delay(1000)替代Thread.Sleep(1000),避免阻塞线程,更符合异步编程最佳实践。 - 合并
attachments != null和attachments.Length > 0的判断,简化代码逻辑。
内容的提问来源于stack exchange,提问作者Salvador Ruiz Guevara
相关产品推荐
相关产品推荐

