Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Put object to Amazon S3 using .net async

I want to convert the AWS S3 async methods into a Task using something like this:

using (var client = AWSClientFactory.CreateAmazonS3Client(accessKey, secretKey))
{
    var request = new PutObjectRequest();
    // ... set request properties ...

    await Task.Factory.FromAsync<PutObjectRequest, PutObjectResponse>(
        client.BeginPutObject,
        client.EndPutObject,
        request,
        null
    );
}

However, I get the following exception:

System.ArgumentException: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at Amazon.S3.AmazonS3Client.getResponseCallback[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.endOperation[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.EndPutObject(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)

Is my call to FromAsync incorrect or is something else going wrong here?

P.S.

  • .NET Framework 4.5
  • AWSSDK version 1.5.17.0
like image 509
Andrew Davey Avatar asked Apr 15 '13 15:04

Andrew Davey


1 Answers

I am experiencing the same issue. Your FromAsync call is correct. The same issue exists when calling BeginPutObject/EndPutObject directly without the FromAsync wrapper.

The synchronous method AmazonS3Client.PutObject() has this body:

IAsyncResult asyncResult;
asyncResult = invokePutObject(request, null, null, true);
return EndPutObject(asyncResult);

Whereas AmazonS3Client.BeginPutObject says:

return invokePutObject(request, callback, state, false);

Note the last boolean parameter to invokePutObject. This argument is called 'synchronized'. If you call it with synchronized=true, it works (by performing the operation synchronously). If you call it with synchronized=false, under concurrent load, you get the exception you posted.

It's clearly a bug in the AWS SDK that needs further investigation. This post on the AWS forums looks similar, but it might not be the same issue; I'm unsatisfied with the upstream reply there, since concurrent synchronous uploads do work.

ETA: The new AWS SDK version 2.0 (in beta at the time of writing), which requires .Net 4.5, has native FooAsync methods (insted of Begin/EndFoo). It's based on the new System.Net.HttpClient library instead of the old HttpWebRequest. It almost certainly doesn't have this bug, but I haven't tested it yet myself.

like image 143
danarmak Avatar answered Oct 23 '22 08:10

danarmak