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

使用MultipartFormDataContent上传大文件时触发ObjectDisposedException

解决大图片上传时的ObjectDisposedException问题

从你的代码和描述来看,这个问题的核心原因是上传大图片时,原始的stream在异步上传过程中被提前释放了——小图片上传速度快,在stream被回收前就完成了请求,所以没触发异常;而大图片上传耗时久,当stream被外部代码 dispose 时,PostAsync还在尝试读取它,就抛出了Cannot access a disposed object错误。

虽然你确认了client和formData没被释放,但问题出在你传入的stream本身,它的生命周期没有覆盖整个异步上传流程。下面是具体的解决方案和排查思路:

1. 确保原始stream的生命周期覆盖整个上传过程

如果你的stream是从某个using块中创建的(比如读取本地文件的FileStream),很可能在await PostAsync完成前,using块就已经结束并dispose了stream。比如这种错误写法:

// 错误示例:stream在using块结束后被dispose,而异步上传可能还在进行
using(var stream = File.OpenRead("large-image.jpg"))
{
    await UploadProfilePic(stream, "large-image.jpg");
}

改成这样,确保stream在上传完成后再释放:

var stream = File.OpenRead("large-image.jpg");
try
{
    await UploadProfilePic(stream, "large-image.jpg");
}
finally
{
    stream.Dispose();
}

2. 复制stream到MemoryStream中(推荐)

把原始stream的内容复制到内存中的MemoryStream,这样可以完全脱离原始stream的生命周期限制,避免外部代码意外释放它。修改你的上传代码如下:

using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
using (var memoryStream = new MemoryStream())
{
    // 把原始stream复制到MemoryStream
    await stream.CopyToAsync(memoryStream);
    memoryStream.Position = 0; // 重置流指针到开头,确保能被正常读取

    formData.Add(new StreamContent(memoryStream), "ProfileImage", fileName);
    var response = await client.PostAsync(Connection.MakeURL("Account/profilePic"), formData);
    return response;
}

MemoryStream会在using块结束后自动释放,而此时上传请求已经完成,不会有冲突。

3. 排查是否有其他代码触发了stream的dispose

如果上面的方法没用,可以给stream注册Disposed事件,定位是谁提前释放了它:

stream.Disposed += (sender, args) =>
{
    // 在这里打日志或者打断点,查看调用栈
    Console.WriteLine("Stream was disposed! Call stack: " + Environment.StackTrace);
};

通过这个方式可以找到触发dispose的代码位置,针对性修复。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:43:30