使用AWS C# SDK操作DigitalOcean获取对象列表触发ObjectDisposedException
解决AmazonS3Client调用ListObjects时触发的ObjectDisposedException异常
我之前也碰到过一模一样的问题!当调用ListObjects方法获取存储桶对象列表时,突然抛出了System.ObjectDisposedException,提示无法访问已释放的对象。先贴一下和你几乎一致的问题代码:
private string S3_ACCESS_KEY = "blablabla"; private string S3_SECRET_KEY = "blablabla"; private string S3_HOST_ENDPOINT = "https://fra1.digitaloceanspaces.com"; private string S3_BUCKET_NAME = "launchers"; private AmazonS3Client _client; public DO() { AmazonS3Config config = new AmazonS3Config(); config.ServiceURL = S3_HOST_ENDPOINT; _client = new AmazonS3Client(S3_ACCESS_KEY, S3_SECRET_KEY, config); } public List<string> ListObject() { var objects = _client.ListObjects(S3_BUCKET_NAME); // 抛出System.ObjectDisposedException异常 var objectsList = objects.S3Objects.Select(c => c.Key).ToList(); return objectsList; }
核心原因
这个异常的本质是你的AmazonS3Client实例_client在调用ListObjects之前已经被释放了。常见触发场景包括:
- 其他代码中手动调用了
_client.Dispose() - 如果
DO类实现了IDisposable接口,且在Dispose方法中释放了_client,当DO实例被销毁时会连带释放客户端 - 异步环境下的线程安全问题,导致客户端被意外回收
- 客户端实例被GC提前回收(虽然这种情况少见,但确实可能发生)
解决方案
1. 每次调用时创建并管理客户端生命周期
如果你的ListObject方法不是高频调用,最稳妥的方式是在方法内部创建客户端,用using语句自动管理释放:
public List<string> ListObject() { using var config = new AmazonS3Config { ServiceURL = S3_HOST_ENDPOINT }; using var client = new AmazonS3Client(S3_ACCESS_KEY, S3_SECRET_KEY, config); var objects = client.ListObjects(S3_BUCKET_NAME); return objects.S3Objects.Select(c => c.Key).ToList(); }
这样每次调用都会生成全新的客户端实例,用完自动释放,从根源上避免生命周期冲突。
2. 排查意外释放客户端的代码
全局搜索项目,检查是否存在以下情况:
- 手动调用
_client.Dispose()的代码 - 将
DO实例放在using块中使用(如果DO实现了IDisposable) - 其他线程中对
_client的不当操作
3. 改用异步API(推荐)
Amazon SDK官方更推荐使用异步方法,同步API存在一些隐藏的资源管理问题。改成异步版本:
public async Task<List<string>> ListObjectAsync() { using var config = new AmazonS3Config { ServiceURL = S3_HOST_ENDPOINT }; using var client = new AmazonS3Client(S3_ACCESS_KEY, S3_SECRET_KEY, config); var objects = await client.ListObjectsAsync(S3_BUCKET_NAME); return objects.S3Objects.Select(c => c.Key).ToList(); }
异步API不仅性能更优,还能减少同步场景下的资源竞争问题。
4. 依赖注入管理客户端(适用于框架项目)
如果是ASP.NET Core这类框架项目,推荐通过依赖注入让框架管理客户端生命周期:
// 在Program.cs中注册服务 builder.Services.AddAWSService<IAmazonS3>(new AmazonS3Config { ServiceURL = S3_HOST_ENDPOINT });
然后在DO类中注入客户端:
private readonly IAmazonS3 _client; public DO(IAmazonS3 client) { _client = client; }
框架会自动处理客户端的创建、复用和释放,彻底避免Disposed异常。
内容的提问来源于stack exchange,提问作者God Of Penguins
相关产品推荐
相关产品推荐

