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

ASP.NET Core调用blobClient.UploadAsync()遇流关闭错误求助

问题描述

向API发送multipart/form-data请求,请求包含IFormFile属性,控制器代码如下:

[Route("api/[controller]")]
public class HomeController : ControllerBase
{
    private readonly IBlobUploadService _blobUpload;

    public HomeController(IValidator<SubmitFileRequest> validator, IBlobUploadService blobUpload)
    {
        _blobUpload = blobUpload;
    }

    [HttpPost("SubmitFile")]
    public async Task<IActionResult> SubmitFile([FromForm]SubmitFileRequest request)
    {
        _blobUpload.UploadFile(request.File);

        return Ok();
    }
}

对应的Blob上传服务代码:

public interface IBlobUploadService
{
    void UploadFile(IFormFile file);
}

public class BlobUploadService : IBlobUploadService
{
    private string blobConnectionString = "my connection string";
    private string blobContainer = "my container";

    public async void UploadFile(IFormFile file)
    {
        BlobContainerClient container = new BlobContainerClient(blobConnectionString, blobContainer);

        var blobClient = container.GetBlobClient(file.FileName);

        await using (Stream? stream = file.OpenReadStream())
        {
            await blobClient.UploadAsync(stream);
        }
    }
}

执行await blobClient.UploadAsync(stream);时持续抛出异常:

System.AggregateException: 'Retry failed after 6 tries. Retry settings can be adjusted in ClientOptions.Retry or by configuring a custom retry policy in ClientOptions.RetryPolicy. (Error while copying content to a stream.) (Error while copying content to a stream.) (Error while copying content to a stream.) (Error while copying content to a stream.) (Error while copying content to a stream.) (Error while copying content to a stream.)'

Inner Exception 1: RequestFailedException: Error while copying content to a stream.

Inner Exception 2: HttpRequestException: Error while copying content to a stream.

Inner Exception 3: ObjectDisposedException: Cannot access a closed Stream.

更新:仅异步版本上传会触发异常,不使用await调用时可正常运行。

问题分析

核心问题有两个:

  1. async void的误用:UploadFile方法标记为async void,这种写法仅适用于事件处理程序,会导致调用方无法跟踪异步操作的完成状态,且异常无法被正确捕获和传播。
  2. 未等待异步操作完成:控制器的SubmitFile方法中调用_blobUpload.UploadFile(request.File)时没有使用await,导致控制器方法提前返回,ASP.NET Core会立即释放请求上下文相关资源(包括IFormFile对应的流),此时异步上传操作还在进行,就会出现流已被释放的错误。
解决方案

按以下步骤修改代码:

  1. 修改服务接口和实现,将void改为Task
    接口和方法都要改为异步任务返回类型:

    public interface IBlobUploadService
    {
        Task UploadFile(IFormFile file);
    }
    
    public class BlobUploadService : IBlobUploadService
    {
        private string blobConnectionString = "my connection string";
        private string blobContainer = "my container";
    
        // 替换async void为async Task
        public async Task UploadFile(IFormFile file)
        {
            BlobContainerClient container = new BlobContainerClient(blobConnectionString, blobContainer);
    
            var blobClient = container.GetBlobClient(file.FileName);
    
            await using (Stream? stream = file.OpenReadStream())
            {
                await blobClient.UploadAsync(stream);
            }
        }
    }
    
  2. 控制器中等待异步操作完成
    在SubmitFile方法中添加await关键字,确保上传操作完成后再返回响应:

    [HttpPost("SubmitFile")]
    public async Task<IActionResult> SubmitFile([FromForm]SubmitFileRequest request)
    {
        await _blobUpload.UploadFile(request.File);
    
        return Ok();
    }
    
  3. 可选:重置流位置(适配重试机制)
    如果Blob客户端的重试机制需要重新读取流,可在上传前重置流的位置到起始处,避免重试时流已到末尾:

    await using (Stream? stream = file.OpenReadStream())
    {
        stream.Position = 0; // 重置流位置
        await blobClient.UploadAsync(stream);
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:33:23