简体   繁体   中英

Cannot access a disposed object when running function more than once

I have an ASP.NET Core 2.1 application and I am getting the error:

Cannot access a disposed object. Object name: 'Amazon.S3.AmazonS3Client'

when trying to call my AWS S3 read object service. This service works the first time and fails on the second and subsequent times.

I have the following in startup.cs:

services.AddSingleton<IAWSService, AWSService>();
services.AddAWSService<IAmazonS3>();

(I have tried configuring AsScoped() to no effect.)

This is the function that is causing problems:

public class AWSService : IAWSService
{
    private readonly IAmazonS3 _s3Client;

    public AWSService(IAmazonS3 s3Client)
    {
        _s3Client = s3Client;
    }

    public async Task<byte[]> ReadObjectFromS3Async(string bucketName, string keyName)
    {
        try
        {
            GetObjectRequest request = new GetObjectRequest
            {
                BucketName = bucketName,
                Key = keyName
            };

            using (_s3Client)
            {
                MemoryStream ms = new MemoryStream();

                using (var getObjectResponse = await _s3Client.GetObjectAsync(request))
                {
                    getObjectResponse.ResponseStream.CopyTo(ms);
                }
                var download = new FileContentResult(ms.ToArray(), "application/pdf");

                return download.FileContents;
            }

        }
        catch (AmazonS3Exception e)
        {
            Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message);
        }
        catch (Exception e)
        {
            Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
        }
        return null;

    }
}

}

The first time I run the function, a breakpoint shows that this.s3client is not disposed, however subsequent attempts at running this function show that the s3client is disposed, hence the error.

Update

I'm calling this function from a controller:

public class CorrespondenceItemController : Controller
{
    private IAWSService _awsService;

    public CorrespondenceItemController(IAWSService aWSService)
    {
        _awsService = aWSService;
    }

    public async Task<ActionResult<dynamic>> Send([FromBody]CorrespondenceItemSendViewModel model)
    {

        var attachment = await _awsService.ReadObjectFromS3Async(bucket, key)
    }
}

That's because you wrap the _s3Client 's usage in a using block, which disposes the instance afterwards.

Don't do that.

Let your IoC container handle that for you, by not explicitly or implicitly disposing your _s3Client .

It's fine to register your wrapper as a singleton, given the answer to Is the Amazon .NET AWS SDK's AmazonS3 thread safe? is "yes". This means that your application has one instance of your AWSService at any given time, and that class will be using the same instance of IAmazonS3 for all requests.

Then you only need to dispose it at the end of your application lifetime, and your IoC container will handle that.

使用是调用dispose的try / finally块的简写。

This line using (_s3Client) { } is saying, create a client and execute the code within the braces { }. Then call .Dispose() to close it.

This means that your client will be closed/shutdown depending on what the Dispose() method does.

If you want to keep the connection open then you should not have a using block, or alternatively you could change your injected client into a client factory and have it create a new one each call, or manually open/close the connection each time you use it.

 using (_s3Client){} 

once using block complete execution then dispose method will be called

using statement equal to

  var ob = new Object()
 try
 {
   ob = null;
 }
 finally
 {
  if (ob!= null)
    ((IDisposable)ob).Dispose();
 }

Remove using _s3Client, which is getting disposed as you kept it inside a using block. As your objective is to reuse it, do not dispose, simple.

using (var getObjectResponse = await _s3Client.GetObjectAsync(request))
using (MemoryStream ms = new MemoryStream())
{
    getObjectResponse.ResponseStream.CopyTo(ms);
    FileContentResult download = new FileContentResult(ms.ToArray(), "application/pdf");
    return download.FileContents;
}
  • If you want to use your s3Client as Singleton, remove using line. This way, you will have a s3Client object through your application lifetime. Be carefull if s3Client stores any object in it. It may cause a resource problem.

    public class AWSService : IAWSService { private readonly IAmazonS3 _s3Client;

     public AWSService(IAmazonS3 s3Client) { _s3Client = s3Client; } public async Task<byte[]> ReadObjectFromS3Async(string bucketName, string keyName) { try { GetObjectRequest request = new GetObjectRequest { BucketName = bucketName, Key = keyName }; MemoryStream ms = new MemoryStream(); using (var getObjectResponse = await _s3Client.GetObjectAsync(request)) { getObjectResponse.ResponseStream.CopyTo(ms); } var download = new FileContentResult(ms.ToArray(), "application/pdf"); return download.FileContents; } catch (AmazonS3Exception e) { Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message); } catch (Exception e) { Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message); } return null; } 

    }

  • If you want to create a new object for every call, remove s3Client registration from IOC context.

    public class AWSService : IAWSService {

     public async Task<byte[]> ReadObjectFromS3Async(string bucketName, string keyName) { try { GetObjectRequest request = new GetObjectRequest { BucketName = bucketName, Key = keyName }; using (var s3Client= new s3Client()/*I don't know how you create*/) { MemoryStream ms = new MemoryStream(); using (var getObjectResponse = await s3Client.GetObjectAsync(request)) { getObjectResponse.ResponseStream.CopyTo(ms); } var download = new FileContentResult(ms.ToArray(), "application/pdf"); return download.FileContents; } } catch (AmazonS3Exception e) { Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message); } catch (Exception e) { Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message); } return null; } 

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM