Try/Catch未捕获异常:OneDrive异步上传间歇性失败排查
间歇性OneDrive上传失败(无捕获异常/随机代码中断):Task/Async使用排查
问题场景
前端为SPA架构,通过MS Graph API获取邮件数据及Base64格式附件;用户选定邮件后,后端将邮件数据存入数据库,再通过List<IFormFile>调用MS Graph API将附件上传至OneDrive。
当前出现的异常表现:
- 辅助文档间歇性未上传至OneDrive
- 代码中Try/Catch未捕获到任何异常
- 调试时代码有时执行完全正常,有时会在随机位置中断
- 怀疑为Task与Async使用不当导致
相关代码
UploadSupportingDocs方法
public async Task<IActionResult> UploadSupportingDocs(List<IFormFile> files, int mailId) { try { // 省略邮件数据入库逻辑 foreach (var file in files) { // 调用附件上传方法 _oneDriveService.UploadFileStreamAsync(file, targetFolderId); } return Ok("操作完成"); } catch (Exception ex) { return BadRequest($"错误:{ex.Message}"); } }
UploadFileStreamAsync方法
public async Task UploadFileStreamAsync(IFormFile file, string folderId) { try { var stream = file.OpenReadStream(); await _graphServiceClient .Me .Drive .Items[folderId] .ItemWithPath(file.FileName) .Content .PutAsync(stream); stream.Close(); } catch (ServiceException ex) { throw new Exception("OneDrive上传失败", ex); } }
OneDrive依赖注入配置
services.AddSingleton<IOneDriveService, OneDriveService>(); services.AddSingleton<GraphServiceClient>(sp => { // 省略认证逻辑,返回GraphServiceClient实例 });
排查与修复方向
1. 异步操作未正确等待
从提供的UploadSupportingDocs代码看,调用UploadFileStreamAsync时未使用await,属于**火与忘记(fire-and-forget)**操作:
// 错误写法:未等待异步任务完成 _oneDriveService.UploadFileStreamAsync(file, targetFolderId); // 正确写法:必须await等待任务执行完毕 await _oneDriveService.UploadFileStreamAsync(file, targetFolderId);
这种情况下,控制器方法可能在上传任务完成前就返回,导致线程被回收,出现无异常但上传失败的情况。
2. 流资源未正确释放
UploadFileStreamAsync中手动调用stream.Close(),不如用using语句自动释放流资源,避免流提前关闭引发静默失败:
// 正确写法:using自动管理流生命周期 using var stream = file.OpenReadStream(); await _graphServiceClient .Me .Drive .Items[folderId] .ItemWithPath(file.FileName) .Content .PutAsync(stream);
3. 依赖注入生命周期问题
当前GraphServiceClient和IOneDriveService都注册为Singleton,但GraphServiceClient内部包含HTTP客户端和认证状态,并非线程安全,在并发场景下会导致随机异常或中断。应改为Scoped生命周期:
// 正确配置:与请求生命周期绑定 services.AddScoped<IOneDriveService, OneDriveService>(); services.AddScoped<GraphServiceClient>(sp => { // 认证逻辑保持不变 });
4. 异常捕获范围不足
UploadFileStreamAsync仅捕获ServiceException,但流操作可能抛出IOException等其他异常,建议扩大捕获范围或不捕获直接向上抛出,确保上层Try/Catch能处理:
public async Task UploadFileStreamAsync(IFormFile file, string folderId) { using var stream = file.OpenReadStream(); await _graphServiceClient .Me .Drive .Items[folderId] .ItemWithPath(file.FileName) .Content .PutAsync(stream); // 移除局部Try/Catch,让上层统一处理异常 }
5. 并发请求限制
MS Graph API对并发请求有配额限制,若批量上传附件未做并发控制,可能触发静默限流。可添加SemaphoreSlim限制同时上传的数量:
// 在OneDriveService中添加并发控制 private readonly SemaphoreSlim _uploadSemaphore = new SemaphoreSlim(3); // 限制同时3个上传任务 public async Task UploadFileStreamAsync(IFormFile file, string folderId) { await _uploadSemaphore.WaitAsync(); try { using var stream = file.OpenReadStream(); await _graphServiceClient .Me .Drive .Items[folderId] .ItemWithPath(file.FileName) .Content .PutAsync(stream); } finally { _uploadSemaphore.Release(); } }
内容的提问来源于stack exchange,提问作者Qiuzman
相关产品推荐
相关产品推荐

