AWS Developer Tools Blog

Object Lifecycles

When using the AWS SDK for .NET, you may find yourself wondering how to use various components of the SDK and, more importantly, how to properly dispose of resources once you are done with them. This blog post reviews the lifecycles of various SDK objects and the best practices for using them.

Lifecycles

There are three basic lifecycle concerns in the AWS SDK for .NET:

  • Thread safety – Some objects can be used across multiple threads without worrying about errors or data corruption.
  • Disposability – Some objects should be disposed of, either by calling .Dispose() on the object or with a using block.
  • Cacheability – Some objects should be cached or reused, usually because they are expensive to recreate.

Clients

The best-known aspect of the AWS SDK for .NET are the various service clients that you can use to interact with AWS. Client objects are thread safe, disposable, and can be reused. (Client objects are inexpensive, so you are not incurring a large overhead by constructing multiple instances, but it’s not a bad idea to create and reuse a client.)

Here’s a simple example of using an Amazon DynamoDB client to list all the tables in your account. Note that we wrap the client in a using block to make sure it is disposed of, either after the last line of the using block is executed or when an exception is thrown. The last point is why it is a good idea, whenever possible, to wrap disposable objects in a using block.

using(var client = new AmazonDynamoDBClient())
{
    var tableNames = client.ListTables().TableNames;
    Console.WriteLine("My DynamoDB tables: " + string.Join(", ", tableNames));
}

High-level objects

The SDK has a number of high-level abstractions built on top of the various service clients. These helper classes provide extra functionality, such as the Amazon S3 TransferUtility class, which automatically handles multi-part uploads, or the DynamoDBContext class, which allows you to store and load .NET objects in Amazon DynamoDB.

  • Amazon.DynamoDBv2.DocumentModel.Table
  • Amazon.DynamoDBv2.DataModel.DynamoDBContext
  • These classes are thread safe, disposable, and cacheable. Both Table and DynamoDBContext should be reused as much as possible, as these objects create and use caches that are populated either from DynamoDB or reflection, operations that could severely degrade performance if performed often (for instance, by recreating a table or a context for every operation).

  • Amazon.S3.Transfer.TransferUtility
  • Amazon.Glacier.Transfer.ArchiveTransferManager
  • These classes are thread safe and disposable. They can be treated like client objects.

Response objects

Most SDK response objects are simple classes, but in a few cases the response objects that you receive from a service call will be disposable. It is important to be aware of what these results are and to properly dispose of them.

The best-known example of this is GetObjectResponse. This is a response returned from an Amazon S3 GetObject call. It is disposable because it returns back to the caller a stream from Amazon S3 of the content for the object. Here’s an example of how this object should be used and disposed of.

MemoryStream ms = new MemoryStream();
using(var client = new Amazon.S3.AmazonS3Client())
{
    var request = new GetObjectRequest
    {
        BucketName = bucketName, Key = key
    };
    using(var response = client.GetObject(request))
    {
        response.ResponseStream.CopyTo(ms);
    }
}

As you can see, we wrapped both the client and the response in using blocks. This makes sure that we dispose of the underlying .NET web streams. (If these are not properly disposed of, you may eventually not be able to make any service calls at all.)

There are two disposable response objects like this in the SDK: Amazon.S3.Model.GetObjectResponse and Amazon.S3.Model.GetObjectTorrentResponse.