diff --git a/services/storage-service-net/src/StorageService.API/Application/Commands/MultipartUpload/CompleteMultipartUploadCommandHandler.cs b/services/storage-service-net/src/StorageService.API/Application/Commands/MultipartUpload/CompleteMultipartUploadCommandHandler.cs
index d25f4210..42776e86 100644
--- a/services/storage-service-net/src/StorageService.API/Application/Commands/MultipartUpload/CompleteMultipartUploadCommandHandler.cs
+++ b/services/storage-service-net/src/StorageService.API/Application/Commands/MultipartUpload/CompleteMultipartUploadCommandHandler.cs
@@ -93,7 +93,9 @@ public class CompleteMultipartUploadCommandHandler
fileSizeBytes: upload.TotalSizeBytes,
userId: upload.UserId,
provider: provider.ProviderType,
- accessLevel: FileAccessLevel.Private // TODO: Get from upload metadata
+ // EN: Multipart aggregate currently does not persist access-level metadata.
+ // VI: Aggregate multipart hiện chưa lưu metadata access-level.
+ accessLevel: FileAccessLevel.Private
);
await _context.StorageFiles.AddAsync(storageFile, cancellationToken);
diff --git a/services/storage-service-net/src/StorageService.Infrastructure/Storage/AliyunOssStorageProvider.cs b/services/storage-service-net/src/StorageService.Infrastructure/Storage/AliyunOssStorageProvider.cs
index 430d1719..5e7a5171 100644
--- a/services/storage-service-net/src/StorageService.Infrastructure/Storage/AliyunOssStorageProvider.cs
+++ b/services/storage-service-net/src/StorageService.Infrastructure/Storage/AliyunOssStorageProvider.cs
@@ -3,6 +3,8 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Infrastructure.Configuration;
+using OssPartETag = Aliyun.OSS.PartETag;
+using System.Linq;
namespace StorageService.Infrastructure.Storage;
@@ -171,9 +173,33 @@ public class AliyunOssStorageProvider : IStorageProvider
string contentType,
CancellationToken cancellationToken = default)
{
- // TODO: Implement using Aliyun OSS InitiateMultipartUpload
- _logger.LogWarning("Multipart upload for Aliyun OSS not yet implemented");
- throw new NotImplementedException("Multipart upload will be implemented in next phase");
+ try
+ {
+ EnsureBucketExistsAsync(bucketName, cancellationToken).Wait(cancellationToken);
+
+ var request = new InitiateMultipartUploadRequest(bucketName, objectKey)
+ {
+ ContentType = contentType
+ };
+
+ var response = _ossClient.InitiateMultipartUpload(request);
+ _logger.LogInformation(
+ "Initiated Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
+ bucketName,
+ objectKey,
+ response.UploadId);
+
+ return Task.FromResult(response.UploadId);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(
+ ex,
+ "Failed to initiate Aliyun OSS multipart upload: {Bucket}/{ObjectKey}",
+ bucketName,
+ objectKey);
+ throw;
+ }
}
///
@@ -185,9 +211,38 @@ public class AliyunOssStorageProvider : IStorageProvider
Stream dataStream,
CancellationToken cancellationToken = default)
{
- // TODO: Implement using Aliyun OSS UploadPart
- _logger.LogWarning("Upload part for Aliyun OSS not yet implemented");
- throw new NotImplementedException("Upload part will be implemented in next phase");
+ try
+ {
+ var request = new UploadPartRequest(bucketName, objectKey, uploadId)
+ {
+ InputStream = dataStream,
+ PartSize = dataStream.Length,
+ PartNumber = partNumber
+ };
+
+ var response = _ossClient.UploadPart(request);
+ var etag = response.PartETag.ETag;
+
+ _logger.LogInformation(
+ "Uploaded Aliyun OSS multipart part: {Bucket}/{ObjectKey}, UploadId: {UploadId}, Part: {PartNumber}",
+ bucketName,
+ objectKey,
+ uploadId,
+ partNumber);
+
+ return Task.FromResult(etag);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(
+ ex,
+ "Failed to upload Aliyun OSS multipart part: {Bucket}/{ObjectKey}, UploadId: {UploadId}, Part: {PartNumber}",
+ bucketName,
+ objectKey,
+ uploadId,
+ partNumber);
+ throw;
+ }
}
///
@@ -198,9 +253,35 @@ public class AliyunOssStorageProvider : IStorageProvider
List parts,
CancellationToken cancellationToken = default)
{
- // TODO: Implement using Aliyun OSS CompleteMultipartUpload
- _logger.LogWarning("Complete multipart upload for Aliyun OSS not yet implemented");
- throw new NotImplementedException("Complete multipart upload will be implemented in next phase");
+ try
+ {
+ var request = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId);
+ var orderedParts = parts
+ .OrderBy(part => part.PartNumber)
+ .Select(part => new OssPartETag(part.PartNumber, part.ETag))
+ .ToList();
+
+ request.PartETags.AddRange(orderedParts);
+ _ossClient.CompleteMultipartUpload(request);
+
+ _logger.LogInformation(
+ "Completed Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
+ bucketName,
+ objectKey,
+ uploadId);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(
+ ex,
+ "Failed to complete Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
+ bucketName,
+ objectKey,
+ uploadId);
+ throw;
+ }
+
+ return Task.CompletedTask;
}
///
@@ -210,8 +291,28 @@ public class AliyunOssStorageProvider : IStorageProvider
string uploadId,
CancellationToken cancellationToken = default)
{
- // TODO: Implement using Aliyun OSS AbortMultipartUpload
- _logger.LogWarning("Abort multipart upload for Aliyun OSS not yet implemented");
- throw new NotImplementedException("Abort multipart upload will be implemented in next phase");
+ try
+ {
+ var request = new AbortMultipartUploadRequest(bucketName, objectKey, uploadId);
+ _ossClient.AbortMultipartUpload(request);
+
+ _logger.LogInformation(
+ "Aborted Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
+ bucketName,
+ objectKey,
+ uploadId);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(
+ ex,
+ "Failed to abort Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
+ bucketName,
+ objectKey,
+ uploadId);
+ throw;
+ }
+
+ return Task.CompletedTask;
}
}