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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:57:59