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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
}
}
}