Files
Foxel/Services/StorageProvider/S3StorageProvider.cs

178 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Foxel.Services.Attributes;
using Foxel.Services.Interface;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
namespace Foxel.Services.StorageProvider;
[StorageProvider(StorageType.S3)]
public class S3StorageProvider : IStorageProvider
{
private readonly string _accessKey;
private readonly string _secretKey;
private readonly string _bucketName;
private readonly string _region;
private readonly string _endpoint;
private readonly bool _usePathStyleUrls;
private readonly string _cdnUrl;
public S3StorageProvider(IConfigService configService)
{
_accessKey = configService["Storage:S3StorageAccessKey"];
_secretKey = configService["Storage:S3StorageSecretKey"];
_bucketName = configService["Storage:S3StorageBucketName"];
_region = configService["Storage:S3StorageRegion"];
_cdnUrl = configService["Storage:S3StorageCdnUrl"];
_endpoint = configService["Storage:S3StorageEndpoint"];
_usePathStyleUrls = bool.TryParse(configService["Storage:S3StorageUsePathStyleUrls"], out var usePathStyle) && usePathStyle;
}
private AmazonS3Client CreateClient()
{
var config = new AmazonS3Config
{
ServiceURL = _endpoint,
UseHttp = !_endpoint.StartsWith("https", StringComparison.OrdinalIgnoreCase),
ForcePathStyle = _usePathStyleUrls
};
if (!string.IsNullOrEmpty(_region) && _endpoint.Contains("amazonaws.com"))
{
config.RegionEndpoint = Amazon.RegionEndpoint.GetBySystemName(_region);
}
return new AmazonS3Client(
_accessKey,
_secretKey,
config
);
}
public async Task<string> SaveAsync(Stream fileStream, string fileName, string contentType)
{
try
{
// 创建唯一的文件存储路径
string currentDate = DateTime.Now.ToString("yyyy/MM");
string ext = Path.GetExtension(fileName);
string objectKey = $"{currentDate}/{Guid.NewGuid()}{ext}";
using var client = CreateClient();
using var transferUtility = new TransferUtility(client);
var uploadRequest = new TransferUtilityUploadRequest
{
InputStream = fileStream,
Key = objectKey,
BucketName = _bucketName,
ContentType = contentType
};
await transferUtility.UploadAsync(uploadRequest);
// 返回文件的路径
return objectKey;
}
catch (Exception ex)
{
Console.WriteLine($"上传文件到S3时出错: {ex.Message}");
throw;
}
}
public async Task DeleteAsync(string storagePath)
{
try
{
if (string.IsNullOrEmpty(storagePath))
return;
using var client = CreateClient();
var deleteRequest = new DeleteObjectRequest
{
BucketName = _bucketName,
Key = storagePath
};
await client.DeleteObjectAsync(deleteRequest);
}
catch (Exception ex)
{
Console.WriteLine($"从S3删除文件时出错: {ex.Message}");
}
}
public string GetUrl(string storagePath)
{
try
{
if (string.IsNullOrEmpty(storagePath))
return "/images/unavailable.gif";
// 如果配置了CDN URL使用CDN
if (!string.IsNullOrEmpty(_cdnUrl))
{
return $"{_cdnUrl}/{storagePath}";
}
// 否则使用S3直链或生成预签名URL
using var client = CreateClient();
var request = new GetPreSignedUrlRequest
{
BucketName = _bucketName,
Key = storagePath,
Expires = DateTime.UtcNow.AddHours(1) // URL有效期1小时
};
return client.GetPreSignedURL(request);
}
catch (Exception ex)
{
Console.WriteLine($"生成S3文件URL时出错: {ex.Message}");
return "/images/unavailable.gif";
}
}
public async Task<string> DownloadFileAsync(string storagePath)
{
try
{
if (string.IsNullOrEmpty(storagePath))
{
throw new ArgumentException("存储路径不能为空");
}
// 创建临时目录
var tempDir = Path.Combine(Path.GetTempPath(), "FoxelS3Temp");
if (!Directory.Exists(tempDir))
{
Directory.CreateDirectory(tempDir);
}
// 创建临时文件名
string fileName = Path.GetFileName(storagePath);
string tempFilePath = Path.Combine(tempDir, fileName);
// 下载文件
using var client = CreateClient();
var request = new GetObjectRequest
{
BucketName = _bucketName,
Key = storagePath
};
using var response = await client.GetObjectAsync(request);
await using var fileStream = new FileStream(tempFilePath, FileMode.Create);
await response.ResponseStream.CopyToAsync(fileStream);
return tempFilePath;
}
catch (Exception ex)
{
Console.WriteLine($"从S3下载文件时出错: {ex.Message}");
throw;
}
}
}