- Làm sao để upload file lên AWS S3?
- Làm sao để download file từ S3?
- Làm sao để delete file trong S3?
- Presigned URL là gì và khi nào sử dụng?
- Cách cấu hình S3 client trong ASP.NET Core?
dotnet add package AWSSDK.S3
// Program.cs
builder.Services.AddAWSService<IAmazonS3>(new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1
});
// Hoặc sử dụng options pattern
builder.Services.Configure<AwsS3Options>(
builder.Configuration.GetSection("AWS:S3"));
// Cấu hình trong appsettings.json
/*
{
"AWS": {
"S3": {
"BucketName": "my-bucket",
"Region": "us-east-1"
}
}
}
*/
// Sử dụng AWS credentials
var credentials = new BasicAWSCredentials("access-key", "secret-key");
builder.Services.AddAWSService<IAmazonS3>(new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1
}, credentials);
// Hoặc sử dụng IAM role (trên EC2, Lambda)
builder.Services.AddAWSService<IAmazonS3>();
public class S3Service
{
private readonly IAmazonS3 _s3Client;
public S3Service(IAmazonS3 s3Client)
{
_s3Client = s3Client;
}
public async Task<string> UploadFileAsync(Stream fileStream, string key)
{
var request = new PutObjectRequest
{
BucketName = "my-bucket",
Key = key,
InputStream = fileStream,
ContentType = "application/octet-stream"
};
var response = await _s3Client.PutObjectAsync(request);
return $"https://my-bucket.s3.amazonaws.com/{key}";
}
}
public async Task<string> UploadWithMetadataAsync(
Stream fileStream,
string key,
string contentType,
Dictionary<string, string> metadata)
{
var request = new PutObjectRequest
{
BucketName = "my-bucket",
Key = key,
InputStream = fileStream,
ContentType = contentType
};
// Thêm metadata
foreach (var item in metadata)
{
request.Metadata[item.Key] = item.Value;
}
await _s3Client.PutObjectAsync(request);
return key;
}
public async Task<string> UploadLargeFileAsync(string filePath, string key)
{
var fileInfo = new FileInfo(filePath);
const int partSize = 5 * 1024 * 1024; // 5MB
var initiateRequest = new CreateMultipartUploadRequest
{
BucketName = "my-bucket",
Key = key,
ContentType = "application/octet-stream"
};
var initiateResponse = await _s3Client.CreateMultipartUploadAsync(initiateRequest);
var uploadParts = new List<UploadPartResponse>();
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var buffer = new byte[partSize];
var partNumber = 1;
try
{
while (fileStream.Position < fileInfo.Length)
{
var bytesRead = await fileStream.ReadAsync(buffer, 0, partSize);
var partRequest = new UploadPartRequest
{
BucketName = "my-bucket",
Key = key,
UploadId = initiateResponse.UploadId,
PartNumber = partNumber,
InputStream = new MemoryStream(buffer, 0, bytesRead),
PartSize = bytesRead
};
var uploadResponse = await _s3Client.UploadPartAsync(partRequest);
uploadParts.Add(uploadResponse);
partNumber++;
}
var completeRequest = new CompleteMultipartUploadRequest
{
BucketName = "my-bucket",
Key = key,
UploadId = initiateResponse.UploadId,
PartETags = uploadParts.Select((p, i) => new PartETag(i + 1, p.ETag)).ToList()
};
await _s3Client.CompleteMultipartUploadAsync(completeRequest);
return key;
}
catch (Exception)
{
await _s3Client.AbortMultipartUploadAsync(new AbortMultipartUploadRequest
{
BucketName = "my-bucket",
Key = key,
UploadId = initiateResponse.UploadId
});
throw;
}
finally
{
fileStream.Dispose();
}
}
public async Task<Stream> DownloadFileAsync(string key)
{
var request = new GetObjectRequest
{
BucketName = "my-bucket",
Key = key
};
var response = await _s3Client.GetObjectAsync(request);
return response.ResponseStream;
}
public async Task DownloadToFileAsync(string key, string localPath)
{
var request = new GetObjectRequest
{
BucketName = "my-bucket",
Key = key
};
var response = await _s3Client.GetObjectAsync(request);
using var writer = new FileStream(localPath, FileMode.Create);
await response.ResponseStream.CopyToAsync(writer);
}
public string GetFileUrl(string key, TimeSpan? expiry = null)
{
var request = new GetPreSignedUrlRequest
{
BucketName = "my-bucket",
Key = key,
Expires = DateTime.UtcNow.Add(expiry ?? TimeSpan.FromHours(1))
};
return _s3Client.GetPreSignedURL(request);
}
public async Task DeleteFileAsync(string key)
{
var request = new DeleteObjectRequest
{
BucketName = "my-bucket",
Key = key
};
await _s3Client.DeleteObjectAsync(request);
}
public async Task DeleteFilesAsync(List<string> keys)
{
var objects = keys.Select(key => new KeyVersion { Key = key }).ToList();
var request = new DeleteObjectsRequest
{
BucketName = "my-bucket",
Objects = objects
};
var response = await _s3Client.DeleteObjectsAsync(request);
}
public async Task DeleteFolderAsync(string prefix)
{
// List all objects with the prefix
var listRequest = new ListObjectsV2Request
{
BucketName = "my-bucket",
Prefix = prefix
};
var objectsToDelete = new List<KeyVersion>();
var response = await _s3Client.ListObjectsV2Async(listRequest);
foreach (var s3Object in response.S3Objects)
{
objectsToDelete.Add(new KeyVersion { Key = s3Object.Key });
}
if (objectsToDelete.Any())
{
var deleteRequest = new DeleteObjectsRequest
{
BucketName = "my-bucket",
Objects = objectsToDelete
};
await _s3Client.DeleteObjectsAsync(deleteRequest);
}
}
public async Task<List<S3Object>> ListFilesAsync(string prefix = "")
{
var request = new ListObjectsV2Request
{
BucketName = "my-bucket",
Prefix = prefix
};
var response = await _s3Client.ListObjectsV2Async(request);
return response.S3Objects.ToList();
}
public async Task<List<S3Object>> ListAllFilesAsync(string prefix = "")
{
var files = new List<S3Object>();
var request = new ListObjectsV2Request
{
BucketName = "my-bucket",
Prefix = prefix
};
ListObjectsV2Response response;
do
{
response = await _s3Client.ListObjectsV2Async(request);
files.AddRange(response.S3Objects);
request.ContinuationToken = response.NextContinuationToken;
} while (response.IsTruncated);
return files;
}
public string GeneratePresignedUrl(string key, TimeSpan expiry)
{
var request = new GetPreSignedUrlRequest
{
BucketName = "my-bucket",
Key = key,
Expires = DateTime.UtcNow.Add(expiry)
};
return _s3Client.GetPreSignedURL(request);
}
public string GenerateUploadUrl(string key, string contentType, TimeSpan expiry)
{
var request = new PutObjectRequest
{
BucketName = "my-bucket",
Key = key,
ContentType = contentType
};
// Get presigned URL for upload
return _s3Client.GetPreSignedURL(request);
}
// Sử dụng S3 Standard cho frequently accessed files
var request = new PutObjectRequest
{
BucketName = "my-bucket",
Key = key,
StorageClass = S3StorageClass.Standard
};
// Sử dụng S3 Standard-IA cho infrequently accessed files
request.StorageClass = S3StorageClass.StandardInfrequentAccess;
// Sử dụng S3 Glacier cho archival files
request.StorageClass = S3StorageClass.Glacier;
// Server-side encryption với AWS-managed key
var request = new PutObjectRequest
{
BucketName = "my-bucket",
Key = key,
ServerSideEncryptionMethod = ServerSideEncryptionMethod.AES256
};
// Hoặc với KMS key
request.ServerSideEncryptionMethod = ServerSideEncryptionMethod.AWSKMS;
request.ServerSideEncryptionKeyManagementServiceKeyId = kmsKeyId;
// IAM Policy example
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
try
{
await _s3Client.PutObjectAsync(request);
}
catch (AmazonS3Exception ex)
{
// Handle S3-specific errors
Console.WriteLine($"S3 Error: {ex.ErrorCode} - {ex.Message}");
throw;
}
catch (Exception ex)
{
// Handle general errors
Console.WriteLine($"Error: {ex.Message}");
throw;
}