Как загрузить поток файла в AWS S3 в ASP.NET? - PullRequest
0 голосов
/ 08 марта 2019

Я очень новичок в AWS S3 и пытаюсь загрузить большой файл по частям. Из пользовательского интерфейса я отправляю фрагментированные данные файла (blob) в службу WCF, откуда я буду загружать их в S3 с помощью MultiPartAPI. Обратите внимание, что файл может быть в ГБ. Вот почему я делаю куски файла и загружаю его на S3.

public UploadPartResponse UploadChunk(Stream stream, string fileName, string uploadId, List<PartETag> eTags, int partNumber, bool lastPart)
{
    stream.Position = 0; // Throwing Exceptions

    //Step 1: build and send a multi upload request
    if (partNumber == 1)
    {
        var initiateRequest = new InitiateMultipartUploadRequest
        {
            BucketName = _settings.Bucket,
            Key = fileName
        };

        var initResponse = _s3Client.InitiateMultipartUpload(initiateRequest);
        uploadId = initResponse.UploadId;
    }

    //Step 2: upload each chunk (this is run for every chunk unlike the other steps which are run once)
    var uploadRequest = new UploadPartRequest
                        {
                            BucketName = _settings.Bucket,
                            Key = fileName,
                            UploadId = uploadId,
                            PartNumber = partNumber,
                            InputStream = stream,
                            IsLastPart = lastPart,
                            PartSize = stream.Length // Throwing Exceptions
                        };

    var response = _s3Client.UploadPart(uploadRequest);

    //Step 3: build and send the multipart complete request
    if (lastPart)
    {
        eTags.Add(new PartETag
        {
            PartNumber = partNumber,
            ETag = response.ETag
        });

        var completeRequest = new CompleteMultipartUploadRequest
        {
            BucketName = _settings.Bucket,
            Key = fileName,
            UploadId = uploadId,
            PartETags = eTags
        };

        try
        {
            _s3Client.CompleteMultipartUpload(completeRequest);
        }
        catch
        {
            //do some logging and return null response
            return null;
        }
    }

    response.ResponseMetadata.Metadata["uploadid"] = uploadRequest.UploadId;
    return response;
}

Здесь stream.Position = 0 и stream.Length , генерирующие исключения, как показано ниже:

в System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.get_Length ()

Тогда я увидел, что stream.CanSeek равен false .

Нужно ли мне буферизовать весь поток, предварительно загрузив его в память, чтобы он работал?

Обновление: Я делаю ниже, и это работает, но не знаю, эффективно это или нет.

    var ms = new MemoryStream();
    stream.CopyTo(ms);
    ms.Position = 0;

Есть ли другой способ сделать это? Заранее спасибо.

1 Ответ

0 голосов
/ 08 марта 2019

Это честный способ сделать это, но я выбрал другой подход, загружая напрямую в S3, используя подписанные URL-адреса. Это дает преимущество, заключающееся в том, что вы снимаете нагрузку с вашего сервера и снижаете скорость передачи данных.

В зависимости от вашего приложения, возможно, стоит подумать об этом:

В C # получите предопределенный URL:

public string GetPreSignedUrl(string bucketName, string keyPrefix, string fileName)
{
    var client = new AmazonS3Client(_credentials, _region);
    var keyName = $"{keyPrefix}/{fileName}";
    var preSignedUrlRequest = new GetPreSignedUrlRequest()
    {
        BucketName = bucketName,
        Key = keyName,
        Expires = DateTime.Now.AddMinutes(5),
        Protocol = (Protocol.HTTPS)
    };
    return client.GetPreSignedURL(preSignedUrlRequest);
}

Это создает URL-адрес для загрузки клиентом непосредственно на S3, который необходимо передать в пользовательский интерфейс. Затем вы можете использовать многоэлементную загрузку на предварительно назначенный URL.

Вот хороший пример многочастной загрузки с использованием axious: https://github.com/prestonlimlianjie/aws-s3-multipart-presigned-upload/blob/master/frontend/pages/index.js

...