in Application/UI/Blazor/ImageRecognition/FileUploader.cs [34:153]
public async Task<string> UploadFileAsync(Stream stream, Action<UploadEvent> callback)
{
var objectKey = $"{_appOptions.UploadBucketPrefix}/{Guid.NewGuid()}";
_logger.LogInformation($"Start uploading to {objectKey}");
var initateResponse = await _s3Client.InitiateMultipartUploadAsync(new InitiateMultipartUploadRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey
});
_logger.LogInformation($"Initiated multi part upload with id {initateResponse.UploadId}");
try
{
using var inputStream = stream;
var partETags = new List<PartETag>();
var readBuffer = ArrayPool<byte>.Shared.Rent(READ_BUFFER_SIZE);
var partBuffer = ArrayPool<byte>.Shared.Rent(PART_SIZE + READ_BUFFER_SIZE * 3);
var callbackEvent = new UploadEvent();
var nextUploadBuffer = new MemoryStream(partBuffer);
try
{
var partNumber = 1;
int readCount;
while ((readCount = await inputStream.ReadAsync(readBuffer, 0, readBuffer.Length)) != 0)
{
callbackEvent.UploadBytes += readCount;
callback?.Invoke(callbackEvent);
await nextUploadBuffer.WriteAsync(readBuffer, 0, readCount);
if (PART_SIZE < nextUploadBuffer.Position)
{
var isLastPart = readCount == READ_BUFFER_SIZE;
var partSize = nextUploadBuffer.Position;
nextUploadBuffer.Position = 0;
var partResponse = await _s3Client.UploadPartAsync(new UploadPartRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey,
UploadId = initateResponse.UploadId,
InputStream = nextUploadBuffer,
PartSize = partSize,
PartNumber = partNumber,
IsLastPart = isLastPart
});
_logger.LogInformation(
$"Uploaded part {partNumber}. (Last part = {isLastPart}, Part size = {partSize}, Upload Id: {initateResponse.UploadId}");
partETags.Add(new PartETag
{PartNumber = partResponse.PartNumber, ETag = partResponse.ETag});
partNumber++;
nextUploadBuffer = new MemoryStream(partBuffer);
callbackEvent.UploadParts++;
callback?.Invoke(callbackEvent);
}
}
if (nextUploadBuffer.Position != 0)
{
var partSize = nextUploadBuffer.Position;
nextUploadBuffer.Position = 0;
var partResponse = await _s3Client.UploadPartAsync(new UploadPartRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey,
UploadId = initateResponse.UploadId,
InputStream = nextUploadBuffer,
PartSize = partSize,
PartNumber = partNumber,
IsLastPart = true
});
_logger.LogInformation(
$"Uploaded final part. (Part size = {partSize}, Upload Id: {initateResponse.UploadId})");
partETags.Add(new PartETag {PartNumber = partResponse.PartNumber, ETag = partResponse.ETag});
callbackEvent.UploadParts++;
callback?.Invoke(callbackEvent);
}
}
finally
{
ArrayPool<byte>.Shared.Return(partBuffer);
ArrayPool<byte>.Shared.Return(readBuffer);
}
await _s3Client.CompleteMultipartUploadAsync(new CompleteMultipartUploadRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey,
UploadId = initateResponse.UploadId,
PartETags = partETags
});
_logger.LogInformation(
$"Completed multi part upload. (Part count: {partETags.Count}, Upload Id: {initateResponse.UploadId})");
}
catch (Exception e)
{
await _s3Client.AbortMultipartUploadAsync(new AbortMultipartUploadRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey,
UploadId = initateResponse.UploadId
});
_logger.LogError($"Error uploading to S3 with error: {e.Message}");
throw;
}
return _s3Client.GetPreSignedURL(new GetPreSignedUrlRequest
{
BucketName = _appOptions.PhotoStorageBucket,
Key = objectKey,
Verb = HttpVerb.GET,
Expires = DateTime.UtcNow.AddDays(1)
});
}