private static void UploadPartCallback(IAsyncResult ar) { var result = client.EndUploadPart(ar); var wrappedContext = (UploadPartContextWrapper)ar.AsyncState; wrappedContext.PartStream.Close(); var ctx = wrappedContext.Context; lock (ctx.SyncLock) { var partETags = ctx.PartETags; partETags.Add(new PartETag(wrappedContext.PartNumber, result.ETag)); ctx.CompletedParts++; Console.WriteLine("finish {0}/{1}", ctx.CompletedParts, ctx.TotalParts); if (ctx.CompletedParts == ctx.TotalParts) { partETags.Sort((e1, e2) => (e1.PartNumber - e2.PartNumber)); var completeMultipartUploadRequest = new CompleteMultipartUploadRequest(ctx.BucketName, ctx.ObjectName, ctx.UploadId); foreach (var partETag in partETags) { completeMultipartUploadRequest.PartETags.Add(partETag); } var completeMultipartUploadResult = client.CompleteMultipartUpload(completeMultipartUploadRequest); Console.WriteLine(@"Async upload multipart result : " + completeMultipartUploadResult.Location); ctx.WaitEvent.Set(); } } }