You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
6.7 KiB
C#

using OnceMi.AspNetCore.OSS;
namespace Admin.NET.Core.Service;
/// <summary>
/// OSS服务管理器接口
/// </summary>
public interface IOSSServiceManager : IDisposable
{
/// <summary>
/// 获取OSS服务实例
/// </summary>
/// <param name="provider">存储提供者配置</param>
/// <returns></returns>
Task<IOSSService> GetOSSServiceAsync(SysFileProvider provider);
/// <summary>
/// 清除缓存
/// </summary>
void ClearCache();
}
/// <summary>
/// OSS服务管理器实现
/// </summary>
public class OSSServiceManager : IOSSServiceManager, ITransient
{
private readonly IServiceProvider _serviceProvider;
private readonly ConcurrentDictionary<string, IOSSService> _ossServiceCache;
private readonly object _lockObject = new object();
private bool _disposed = false;
public OSSServiceManager(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_ossServiceCache = new ConcurrentDictionary<string, IOSSService>();
}
/// <summary>
/// 获取OSS服务实例带缓存
/// </summary>
/// <param name="provider">存储提供者配置</param>
/// <returns></returns>
public async Task<IOSSService> GetOSSServiceAsync(SysFileProvider provider)
{
if (provider == null)
throw new ArgumentNullException(nameof(provider));
var cacheKey = provider.ConfigKey;
// 尝试从缓存获取
if (_ossServiceCache.TryGetValue(cacheKey, out var cachedService))
{
return cachedService;
}
// 验证配置
if (!await ValidateConfigurationAsync(provider))
{
throw new InvalidOperationException($"OSS提供者配置无效: {provider.DisplayName}");
}
// 线程安全地创建新服务
lock (_lockObject)
{
// 双重检查锁定模式
if (_ossServiceCache.TryGetValue(cacheKey, out cachedService))
{
return cachedService;
}
// 转换配置并创建服务
var ossOptions = ConvertToOSSOptions(provider);
var ossService = CreateOSSService(ossOptions);
// 添加到缓存
_ossServiceCache.TryAdd(cacheKey, ossService);
return ossService;
}
}
/// <summary>
/// 创建OSS服务实例
/// </summary>
/// <param name="options">OSS配置选项</param>
/// <returns></returns>
private IOSSService CreateOSSService(OSSOptions options)
{
ArgumentNullException.ThrowIfNull(options);
try
{
// 使用现有的IOSSServiceFactory但需要先注册配置
var providerName = Enum.GetName(options.Provider);
var configSectionName = $"TempOSS_{Guid.NewGuid():N}";
// 创建临时配置
var configData = new Dictionary<string, string>
{
[$"{configSectionName}:Provider"] = providerName,
[$"{configSectionName}:Endpoint"] = options.Endpoint ?? "",
[$"{configSectionName}:AccessKey"] = options.AccessKey ?? "",
[$"{configSectionName}:SecretKey"] = options.SecretKey ?? "",
[$"{configSectionName}:Region"] = options.Region ?? "",
[$"{configSectionName}:IsEnableHttps"] = options.IsEnableHttps.ToString(),
[$"{configSectionName}:IsEnableCache"] = options.IsEnableCache.ToString()
};
var tempConfig = new ConfigurationBuilder()
.AddInMemoryCollection(configData)
.Build();
// 创建临时服务集合,但不立即释放
var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(tempConfig);
services.AddLogging();
services.AddOSSService(providerName, configSectionName);
// 构建服务提供者并创建OSS服务
var tempServiceProvider = services.BuildServiceProvider();
var ossServiceFactory = tempServiceProvider.GetRequiredService<IOSSServiceFactory>();
var ossService = ossServiceFactory.Create(providerName);
// 注意不要释放tempServiceProvider因为ossService可能依赖它
// 这里我们接受这个内存开销,因为缓存会减少创建频率
return ossService;
}
catch (Exception ex)
{
throw Oops.Oh($"创建OSS服务失败: {ex.Message}");
}
}
/// <summary>
/// 验证配置
/// </summary>
/// <param name="provider">存储提供者配置</param>
/// <returns></returns>
private Task<bool> ValidateConfigurationAsync(SysFileProvider provider)
{
if (provider == null) return Task.FromResult(false);
// 基本字段验证
var isValid = !string.IsNullOrWhiteSpace(provider.Provider) &&
!string.IsNullOrWhiteSpace(provider.BucketName) &&
!string.IsNullOrWhiteSpace(provider.AccessKey) &&
!string.IsNullOrWhiteSpace(provider.SecretKey);
// Minio额外需要Endpoint
if (provider.Provider.ToUpper() == "MINIO")
{
isValid = isValid && !string.IsNullOrWhiteSpace(provider.Endpoint);
}
return Task.FromResult(isValid);
}
/// <summary>
/// 将SysFileProvider转换为OSSOptions
/// </summary>
/// <param name="provider"></param>
/// <returns></returns>
private OSSOptions ConvertToOSSOptions(SysFileProvider provider)
{
if (provider == null)
throw new ArgumentNullException(nameof(provider));
var ossOptions = new OSSOptions
{
Provider = Enum.Parse<OSSProvider>(provider.Provider),
Endpoint = provider.Endpoint,
Region = provider.Region,
IsEnableHttps = provider.IsEnableHttps ?? true,
IsEnableCache = provider.IsEnableCache ?? true
};
// 设置认证信息(所有提供者现在都使用统一的字段)
ossOptions.AccessKey = provider.AccessKey;
ossOptions.SecretKey = provider.SecretKey;
return ossOptions;
}
/// <summary>
/// 清除缓存
/// </summary>
public void ClearCache()
{
lock (_lockObject)
{
_ossServiceCache.Clear();
}
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (!_disposed)
{
lock (_lockObject)
{
_ossServiceCache.Clear();
}
_disposed = true;
}
}
}