AWS Developer Tools Blog
Working with Amazon S3 Object Versions and the AWS SDK for .NET
Amazon S3 allows you to enable versioning for a bucket. You can enable or disable versioning with the SDK by calling the PutBucketVersioning
method. Note, all code samples were written for our new version 2 of the SDK. Users of version 1 of the SDK will notice some slight name changes.
s3Client.PutBucketVersioning(new PutBucketVersioningRequest
{
BucketName = versionBucket,
VersioningConfig = new S3BucketVersioningConfig() { Status = VersionStatus.Enabled }
});
Once versioning is enabled, every PutObject
call with the same key will add a new version of the object with a different version ID instead of overwriting the object. For example, running the code below will create three versions of the “sample.txt” object. The sleeps are added to give a more obvious difference in the timestamps.
var putRequest = new PutObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt",
ContentBody = "Content For Version 1"
};
s3Client.PutObject(putRequest);
Thread.Sleep(TimeSpan.FromSeconds(10));
s3Client.PutObject(new PutObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt",
ContentBody = "Content For Version 2"
});
Thread.Sleep(TimeSpan.FromSeconds(10));
s3Client.PutObject(new PutObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt",
ContentBody = "Content For Version 3"
});
Now, if you call the GetObject
method without specifying a version ID like this:
var getRequest = new GetObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt"
};
using (GetObjectResponse getResponse = s3Client.GetObject(getRequest))
using (StreamReader reader = new StreamReader(getResponse.ResponseStream))
{
Console.WriteLine(reader.ReadToEnd());
}
// Outputs:
Content For Version 3
It will print out the contents of the last object that was put into the bucket.
Use the ListVersions
method to get the list of versions.
var listResponse = s3Client.ListVersions(new ListVersionsRequest
{
BucketName = versionBucket,
Prefix = "sample.txt"
});
foreach(var version in listResponse.Versions)
{
Console.WriteLine("Key: {0}, Version ID: {1}, IsLatest: {2}, Modified: {3}",
version.Key, version.VersionId, version.IsLatest, version.LastModified);
}
// Output:
Key: sample.txt, Version ID: nx5sVCpUSdpHzPBpOICF.eELc2nUsm3c, IsLatest: True, Modified: 10/29/2013 4:45:07 PM
Key: sample.txt, Version ID: LOgcIIrvtM0ZqYfkvfRz3UMdgdmRXNWE, IsLatest: False, Modified: 10/29/2013 4:44:56 PM
Key: sample.txt, Version ID: XxnZRKXHZ7cHYiogeCHXXxccojj9DLK5, IsLatest: False, Modified: 10/29/2013 4:44:46 PM
To get a specific version of an object, you simply need to specify the VersionId
property when performing a GetObject
.
var earliestVersion = listResponse.Versions.OrderBy(x => x.LastModified).First();
var getRequest = new GetObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt",
VersionId = earliestVersion.VersionId
};
using(GetObjectResponse getResponse = s3Client.GetObject(getRequest))
using(StreamReader reader = new StreamReader(getResponse.ResponseStream))
{
Console.WriteLine(reader.ReadToEnd());
}
// Outputs:
Content For Version 1
Deleting an object that is versioned works differently than the non-versioned objects. If you call delete like this:
s3Client.DeleteObject(new DeleteObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt"
});
and then try to do a GetObject
for the “sample.txt” object, S3 will return an error that the object doesn’t exist. What S3 actually does when you call delete for a versioned object is insert a delete marker. You can see this if you list the versions again.
var listResponse = s3Client.ListVersions(new ListVersionsRequest
{
BucketName = versionBucket,
Prefix = "sample.txt"
});
foreach (var version in listResponse.Versions)
{
Console.WriteLine("Key: {0}, Version ID: {1}, IsLatest: {2}, IsDeleteMarker: {3}",
version.Key, version.VersionId, version.IsLatest, version.IsDeleteMarker);
}
// Outputs:
Key: sample.txt, Version ID: YRsryuUODxDujL4Y4iJjRLKweHrV0t2U, IsLatest: True, IsDeleteMarker: True
Key: sample.txt, Version ID: nx5sVCpUSdpHzPBpOICF.eELc2nUsm3c, IsLatest: False, IsDeleteMarker: False
Key: sample.txt, Version ID: LOgcIIrvtM0ZqYfkvfRz3UMdgdmRXNWE, IsLatest: False, IsDeleteMarker: False
Key: sample.txt, Version ID: XxnZRKXHZ7cHYiogeCHXXxccojj9DLK5, IsLatest: False, IsDeleteMarker: False
If you want to delete a specific version of an object, when calling DeleteObject
, set the VersionId
property. This is also how you can restore an object by deleting the delete marker.
var deleteMarkerVersion = listResponse.Versions.FirstOrDefault(x => x.IsDeleteMarker && x.IsLatest);
if (deleteMarkerVersion != null)
{
s3Client.DeleteObject(new DeleteObjectRequest
{
BucketName = versionBucket,
Key = "sample.txt",
VersionId = deleteMarkerVersion.VersionId
});
}
Now, calls to GetObject
for the “sample.txt” object will succeed again.