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

如何解决异步Lambda函数中MemoryStream的已释放对象访问错误

问题:异步执行时访问已释放的IServiceProvider错误

错误现象

同步运行代码一切正常,改为异步并行执行后,调用自定义Azure下载方法DriveItemDownloadAsync时抛出以下错误:

System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.

at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.Identity.Web.TokenAcquisitionAspnetCoreHost.GetEffectiveAuthenticationScheme(String authenticationScheme)
at Microsoft.Identity.Web.TokenAcquisitionAspnetCoreHost.GetOptions(String authenticationScheme, String& effectiveAuthenticationScheme)
at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForUserAsync(IEnumerable1 scopes, String authenticationScheme, String tenantId, String userFlow, ClaimsPrincipal user, TokenAcquisitionOptions tokenAcquisitionOptions)<br>at Microsoft.Identity.Web.DefaultAuthorizationHeaderProvider.CreateAuthorizationHeaderForUserAsync(IEnumerable1 scopes, AuthorizationHeaderProviderOptions downstreamApiOptions, ClaimsPrincipal claimsPrincipal, CancellationToken cancellationToken)
at Microsoft.Identity.Web.TokenAcquisitionAuthenticationProvider.AuthenticateRequestAsync(HttpRequestMessage request)
at Microsoft.Graph.AuthenticationHandler.SendAsync(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Microsoft.Graph.HttpProvider.SendRequestAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)

控制器代码(出错版本)

Task ReportTask = new Task(async () => {
    var reportPathOneDrive = "path.docx";
    var reportPathBox = "path.docx";

    var FileInfo = await oneDrive.DriveItemInfoAsync(SharedDriveID, reportPathOneDrive, "path");

    var memoryStream = await oneDrive.DriveItemDownloadAsync(SharedDriveID, reportPathOneDrive, "path");

    MemoryStream memoryStreamBox = new MemoryStream();
    memoryStream.CopyTo(memoryStreamBox);
    memoryStream.Position = 0;
    memoryStreamBox.Position = 0;

    //add to email
    var attachment = new ARMS.Models.FileAttachment
    {
        FileName = FileInfo.Name.ToString(),
        ContentType = FileInfo.File.MimeType.ToString(),
        ContentBytes = memoryStream.ToArray()
    };

    attachments.Add(attachment);

    var uploadBox = await boxDrive.UploadFileAsync(BoxARMSFolderID, memoryStreamBox, reportPathBox);
});

ReportTask.Start();
List<Task> documentTasks = new List<Task> { ReportTask };

await Task.WhenAll(documentTasks);

出错的DriveItemDownloadAsync方法

public async Task<MemoryStream> DriveItemDownloadAsync(string DriveID, string PathOrDriveItemID, string SearchType)
{
    var tries = 0;
    var maxRetries = 1;

    Stream response = null;
    var MemoryStream = new MemoryStream();

    while (tries <= maxRetries)
    {
        tries++;

        try
        {
            if (SearchType == "path")
            {
                response = await _graphServiceClient.Me.Drives[DriveID].Root
                                .ItemWithPath(PathOrDriveItemID)
                                .Content
                                .Request()
                                .GetAsync();
            }
            else if (SearchType == "id")
            {
                response = await _graphServiceClient.Me.Drives[DriveID]
                                .Items[PathOrDriveItemID]
                                .Content
                                .Request()
                                .GetAsync();
            }

            response.CopyTo(MemoryStream);
            MemoryStream.Position = 0;

            tries = maxRetries + 1;
        }
        catch (ServiceException svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in claims challenge"))
        {
            try
            {
                Console.WriteLine($"{svcex}");
                string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(svcex.ResponseHeaders);
                _consentHandler.ChallengeUser(initialScopes, claimChallenge);
            }
            catch (Exception ex2)
            {
                _consentHandler.HandleException(ex2);
            }
        }
    }

    return MemoryStream;
}

问题根源

你使用new Task(async () => { ... })的方式是错误的:

  • 异步Lambda会被包装成Task<Task>,但你只拿到了外层的Task。当外层任务完成时,内层异步操作可能还在执行,此时控制器的请求上下文(包括IServiceProvider)已经被释放。
  • _graphServiceClient依赖请求上下文的身份认证服务,后续异步操作访问已释放的对象就会抛出错误。
  • 手动调用ReportTask.Start()也是不必要的,异步代码无需手动启动任务。

修复方法

1. 提取独立异步方法

把异步逻辑封装成独立的异步方法,避免直接用异步Lambda创建Task:

async Task ProcessReportAsync()
{
    var reportPathOneDrive = "path.docx";
    var reportPathBox = "path.docx";

    var FileInfo = await oneDrive.DriveItemInfoAsync(SharedDriveID, reportPathOneDrive, "path");

    var memoryStream = await oneDrive.DriveItemDownloadAsync(SharedDriveID, reportPathOneDrive, "path");

    using var memoryStreamBox = new MemoryStream();
    memoryStream.CopyTo(memoryStreamBox);
    memoryStream.Position = 0;
    memoryStreamBox.Position = 0;

    //add to email
    var attachment = new ARMS.Models.FileAttachment
    {
        FileName = FileInfo.Name.ToString(),
        ContentType = FileInfo.File.MimeType.ToString(),
        ContentBytes = memoryStream.ToArray()
    };

    attachments.Add(attachment);

    await boxDrive.UploadFileAsync(BoxARMSFolderID, memoryStreamBox, reportPathBox);
}

2. 正确执行并行任务

在控制器中直接获取任务并等待,无需手动启动:

var reportTask = ProcessReportAsync();
List<Task> documentTasks = new List<Task> { reportTask };

await Task.WhenAll(documentTasks);

额外优化

  • 用using声明memoryStreamBox,确保流被正确释放
  • 如果需要并行多个任务,直接添加多个异步方法返回的Task到列表即可,无需Task.Run(除非任务不依赖请求上下文)

内容的提问来源于stack exchange,提问作者Qiuzman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:12:50