2013-05-30 13 views
6

sử dụng .NET SDK v.1.5.21.0EntityTooSmall trong CompleteMultipartUploadResponse

Tôi đang cố gắng để tải lên một tập tin lớn (63Mb) và tôi đang theo gương tại địa chỉ:

http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html

Nhưng sử dụng một helper thay vì mã lỗ và sử dụng jQuery tập tin Tải

https://github.com/blueimp/jQuery-File-Upload/blob/master/basic-plus.html

những gì tôi có là:

string bucket = "mybucket"; 

long totalSize = long.Parse(context.Request.Headers["X-File-Size"]), 
     maxChunkSize = long.Parse(context.Request.Headers["X-File-MaxChunkSize"]), 
     uploadedBytes = long.Parse(context.Request.Headers["X-File-UloadedBytes"]), 
     partNumber = uploadedBytes/maxChunkSize + 1, 
     fileSize = partNumber * inputStream.Length; 

bool lastPart = inputStream.Length < maxChunkSize; 

// http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html 
if (partNumber == 1) // initialize upload 
{ 
    iView.Utilities.Amazon_S3.S3MultipartUpload.InitializePartToCloud(fileName, bucket); 
} 

try 
{ 
    // upload part 
    iView.Utilities.Amazon_S3.S3MultipartUpload.UploadPartToCloud(fs, fileName, bucket, (int)partNumber, uploadedBytes, maxChunkSize); 

    if (lastPart) 
     // wrap it up and go home 
     iView.Utilities.Amazon_S3.S3MultipartUpload.CompletePartToCloud(fileName, bucket); 

} 
catch (System.Exception ex) 
{ 
    // Huston, we have a problem! 
    //Console.WriteLine("Exception occurred: {0}", exception.Message); 
    iView.Utilities.Amazon_S3.S3MultipartUpload.AbortPartToCloud(fileName, bucket); 
} 

public static class S3MultipartUpload 
{ 
    private static string accessKey = System.Configuration.ConfigurationManager.AppSettings["AWSAccessKey"]; 
    private static string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings["AWSSecretKey"]; 
    private static AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey); 
    public static InitiateMultipartUploadResponse initResponse; 
    public static List<UploadPartResponse> uploadResponses; 

    public static void InitializePartToCloud(string destinationFilename, string destinationBucket) 
    { 
     // 1. Initialize. 
     uploadResponses = new List<UploadPartResponse>(); 

     InitiateMultipartUploadRequest initRequest = 
      new InitiateMultipartUploadRequest() 
      .WithBucketName(destinationBucket) 
      .WithKey(destinationFilename.TrimStart('/')); 

     initResponse = client.InitiateMultipartUpload(initRequest); 
    } 
    public static void UploadPartToCloud(Stream fileStream, string destinationFilename, string destinationBucket, int partNumber, long uploadedBytes, long maxChunkedBytes) 
    { 
     // 2. Upload Parts. 
     UploadPartRequest request = new UploadPartRequest() 
      .WithBucketName(destinationBucket) 
      .WithKey(destinationFilename.TrimStart('/')) 
      .WithUploadId(initResponse.UploadId) 
      .WithPartNumber(partNumber) 
      .WithPartSize(maxChunkedBytes) 
      .WithFilePosition(uploadedBytes) 
      .WithInputStream(fileStream) as UploadPartRequest; 

     uploadResponses.Add(client.UploadPart(request)); 
    } 
    public static void CompletePartToCloud(string destinationFilename, string destinationBucket) 
    { 
     // Step 3: complete. 
     CompleteMultipartUploadRequest compRequest = 
      new CompleteMultipartUploadRequest() 
      .WithBucketName(destinationBucket) 
      .WithKey(destinationFilename.TrimStart('/')) 
      .WithUploadId(initResponse.UploadId) 
      .WithPartETags(uploadResponses); 

     CompleteMultipartUploadResponse completeUploadResponse = 
      client.CompleteMultipartUpload(compRequest); 
    } 
    public static void AbortPartToCloud(string destinationFilename, string destinationBucket) 
    { 
     // abort. 
     client.AbortMultipartUpload(new AbortMultipartUploadRequest() 
       .WithBucketName(destinationBucket) 
       .WithKey(destinationFilename.TrimStart('/')) 
       .WithUploadId(initResponse.UploadId)); 
    } 
} 

maxChunckedSize của tôi là 6Mb (6 * (1024 * 1024)) như tôi đã đọc rằng tối thiểu là 5Mb ...

lý do tại sao tôi nhận "Your proposed upload is smaller than the minimum allowed size" ngoại lệ ? Tôi đang làm gì sai?

Lỗi này là:

<Error> 
    <Code>EntityTooSmall</Code> 
    <Message>Your proposed upload is smaller than the minimum allowed size</Message> 
    <ETag>d41d8cd98f00b204e9800998ecf8427e</ETag> 
    <MinSizeAllowed>5242880</MinSizeAllowed> 
    <ProposedSize>0</ProposedSize> 
    <RequestId>C70E7A23C87CE5FC</RequestId> 
    <HostId>pmhuMXdRBSaCDxsQTHzucV5eUNcDORvKY0L4ZLMRBz7Ch1DeMh7BtQ6mmfBCLPM2</HostId> 
    <PartNumber>1</PartNumber> 
</Error> 

Làm thế nào tôi có thể nhận được ProposedSize nếu tôi đi qua con suối và dòng thời gian?

+0

xóa 'dưới dạng UploadPartRequest' trong cụm từ' UploadPartToCloud' và vòng lặp của bạn trong 'try {}' vì nếu tôi hiểu chính xác bạn cần lặp lại các phần của mình – WiiMaxx

+0

, vòng lặp diễn ra tự động như phần đầu tiên của mã là một trình xử lý trong đó cuộc gọi không đồng bộ sẽ gửi các phần tệp. Tôi có mọi thứ đang hoạt động, nhưng nếu có ai biết câu trả lời, tôi sẵn lòng cho nó điểm thưởng, hoặc tôi sẽ viết câu trả lời đúng sau khi thời gian tiền thưởng kết thúc. – balexandre

+1

nếu bạn có nó chỉ cần viết câu trả lời không cần phải giấu nó :) – WiiMaxx

Trả lời

0

Dưới đây là một giải pháp làm việc cho mới nhất Amazon SDK (như hiện nay: v.1.5.37.0)

Amazon S3 Multipart tải hoạt động như:

  1. Khởi tạo theo yêu cầu sử dụng client.InitiateMultipartUpload(initRequest)
  2. Gửi các đoạn của tệp (vòng lặp cho đến cuối) bằng cách sử dụng client.UploadPart(request)
  3. Hoàn thành yêu cầu sử dụng client.CompleteMultipartUpload(compRequest)
  4. Nếu bất cứ điều gì sai, hãy nhớ để xử lý khách hàng và yêu cầu, cũng bắn lệnh hủy bỏ sử dụng client.AbortMultipartUpload(abortMultipartUploadRequest)

tôi giữ cho khách hàng trong Session khi chúng ta cần điều này cho mỗi đoạn tải lên là tốt, giữ một giữ ETags hiện đang được sử dụng để hoàn tất quá trình.


Bạn có thể thấy một ví dụ và cách đơn giản để làm điều này trong Amazon Docs bản thân, tôi đã kết thúc có một lớp học để làm tất cả mọi thứ, cộng thêm, tôi đã tích hợp với jQuery File Upload Plugin đáng yêu (mã Handler dưới đây cũng).

Các S3MultipartUpload là như sau

public class S3MultipartUpload : IDisposable 
{ 
    string accessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSAccessKey"); 
    string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSSecretKey"); 

    AmazonS3 client; 
    public string OriginalFilename { get; set; } 
    public string DestinationFilename { get; set; } 
    public string DestinationBucket { get; set; } 

    public InitiateMultipartUploadResponse initResponse; 
    public List<PartETag> uploadPartETags; 
    public string UploadId { get; private set; } 

    public S3MultipartUpload(string destinationFilename, string destinationBucket) 
    { 
     if (client == null) 
     { 
      System.Net.WebRequest.DefaultWebProxy = null; // disable proxy to make upload quicker 

      client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey, new AmazonS3Config() 
      { 
       RegionEndpoint = Amazon.RegionEndpoint.EUWest1, 
       CommunicationProtocol = Protocol.HTTP 
      }); 

      this.OriginalFilename = destinationFilename.TrimStart('/'); 
      this.DestinationFilename = string.Format("{0:yyyy}{0:MM}{0:dd}{0:HH}{0:mm}{0:ss}{0:fffff}_{1}", DateTime.UtcNow, this.OriginalFilename); 
      this.DestinationBucket = destinationBucket; 

      this.InitializePartToCloud(); 
     } 
    } 

    private void InitializePartToCloud() 
    { 
     // 1. Initialize. 
     uploadPartETags = new List<PartETag>(); 

     InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(); 
     initRequest.BucketName = this.DestinationBucket; 
     initRequest.Key = this.DestinationFilename; 

     // make it public 
     initRequest.AddHeader("x-amz-acl", "public-read"); 

     initResponse = client.InitiateMultipartUpload(initRequest); 
    } 
    public void UploadPartToCloud(Stream fileStream, long uploadedBytes, long maxChunkedBytes) 
    { 
     int partNumber = uploadPartETags.Count() + 1; // current part 

     // 2. Upload Parts. 
     UploadPartRequest request = new UploadPartRequest(); 
     request.BucketName = this.DestinationBucket; 
     request.Key = this.DestinationFilename; 
     request.UploadId = initResponse.UploadId; 
     request.PartNumber = partNumber; 
     request.PartSize = fileStream.Length; 
     //request.FilePosition = uploadedBytes // remove this line? 
     request.InputStream = fileStream; // as UploadPartRequest; 

     var up = client.UploadPart(request); 
     uploadPartETags.Add(new PartETag() { ETag = up.ETag, PartNumber = partNumber }); 
    } 
    public string CompletePartToCloud() 
    { 
     // Step 3: complete. 
     CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(); 
     compRequest.BucketName = this.DestinationBucket; 
     compRequest.Key = this.DestinationFilename; 
     compRequest.UploadId = initResponse.UploadId; 
     compRequest.PartETags = uploadPartETags; 

     string r = "Something went badly wrong"; 

     using (CompleteMultipartUploadResponse completeUploadResponse = client.CompleteMultipartUpload(compRequest)) 
      r = completeUploadResponse.ResponseXml; 

     return r; 
    } 
    public void AbortPartToCloud() 
    { 
     // abort. 
     client.AbortMultipartUpload(new AbortMultipartUploadRequest() 
     { 
      BucketName = this.DestinationBucket, 
      Key = this.DestinationFilename, 
      UploadId = initResponse.UploadId 
     }); 
    } 

    public void Dispose() 
    { 
     if (client != null) client.Dispose(); 
     if (initResponse != null) initResponse.Dispose(); 
    } 
} 

tôi sử dụng DestinationFilename như file đích để tôi có thể tránh cùng tên, nhưng tôi giữ OriginalFilename như tôi cần thiết sau này.

Sử dụng jQuery File Upload Plugin, tất cả các công trình bên trong một Generic Handler, và quá trình này là một cái gì đó như thế này:

// Upload partial file 
private void UploadPartialFile(string fileName, HttpContext context, List<FilesStatus> statuses) 
{ 
    if (context.Request.Files.Count != 1) 
     throw new HttpRequestValidationException("Attempt to upload chunked file containing more than one fragment per request"); 

    var inputStream = context.Request.Files[0].InputStream; 
    string contentRange = context.Request.Headers["Content-Range"]; // "bytes 0-6291455/14130271" 

    int fileSize = int.Parse(contentRange.Split('/')[1]);, 
     maxChunkSize = int.Parse(context.Request.Headers["X-Max-Chunk-Size"]), 
     uploadedBytes = int.Parse(contentRange.Replace("bytes ", "").Split('-')[0]); 

    iView.Utilities.AWS.S3MultipartUpload s3Upload = null; 

    try 
    { 

     // ###################################################################################### 
     // 1. Initialize Amazon S3 Client 
     if (uploadedBytes == 0) 
     { 
      HttpContext.Current.Session["s3-upload"] = new iView.Utilities.AWS.S3MultipartUpload(fileName, awsBucket); 

      s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"]; 
      string msg = System.String.Format("Upload started: {0} ({1:N0}Mb)", s3Upload.DestinationFilename, (fileSize/1024)); 
      this.Log(msg); 
     } 

     // cast current session object 
     if (s3Upload == null) 
      s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"]; 

     // ###################################################################################### 
     // 2. Send Chunks 
     s3Upload.UploadPartToCloud(inputStream, uploadedBytes, maxChunkSize); 

     // ###################################################################################### 
     // 3. Complete Upload 
     if (uploadedBytes + maxChunkSize > fileSize) 
     { 
      string completeRequest = s3Upload.CompletePartToCloud(); 
      this.Log(completeRequest); // log S3 response 

      s3Upload.Dispose(); // dispose all objects 
      HttpContext.Current.Session["s3-upload"] = null; // we don't need this anymore 
     } 

    } 
    catch (System.Exception ex) 
    { 
     if (ex.InnerException != null) 
      while (ex.InnerException != null) 
       ex = ex.InnerException; 

     this.Log(string.Format("{0}\n\n{1}", ex.Message, ex.StackTrace)); // log error 

     s3Upload.AbortPartToCloud(); // abort current upload 
     s3Upload.Dispose(); // dispose all objects 

     statuses.Add(new FilesStatus(ex.Message)); 
     return; 
    } 

    statuses.Add(new FilesStatus(s3Upload.DestinationFilename, fileSize, "")); 
} 

Hãy ghi nhớ rằng để có một đối tượng Session bên trong một Generic Handler, bạn cần phải thực hiện IRequiresSessionState để xử lý của bạn sẽ trông giống như:

public class UploadHandlerSimple : IHttpHandler, IRequiresSessionState 

Bên fileupload.js (dưới _initXHRData) tôi đã thêm một tiêu đề phụ gọi X-Max-Chunk-Size vì vậy tôi có thể chuyển thông tin này đến Amazon và tính toán nếu đó là phần cuối cùng của tệp được tải lên.


Rời bình luận và thực hiện chỉnh sửa thông minh cho mọi người sử dụng.

0

Tôi đoán bạn đã không đặt độ dài nội dung của phần bên trong hàm UploadPartToCloud().