using OnceMi.AspNetCore.OSS; namespace Admin.NET.Core.Service; /// /// OSS服务管理器接口 /// public interface IOSSServiceManager : IDisposable { /// /// 获取OSS服务实例 /// /// 存储提供者配置 /// Task GetOSSServiceAsync(SysFileProvider provider); /// /// 清除缓存 /// void ClearCache(); } /// /// OSS服务管理器实现 /// public class OSSServiceManager : IOSSServiceManager, ITransient { private readonly IServiceProvider _serviceProvider; private readonly ConcurrentDictionary _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(); } /// /// 获取OSS服务实例(带缓存) /// /// 存储提供者配置 /// public async Task 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; } } /// /// 创建OSS服务实例 /// /// OSS配置选项 /// 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 { [$"{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(tempConfig); services.AddLogging(); services.AddOSSService(providerName, configSectionName); // 构建服务提供者并创建OSS服务 var tempServiceProvider = services.BuildServiceProvider(); var ossServiceFactory = tempServiceProvider.GetRequiredService(); var ossService = ossServiceFactory.Create(providerName); // 注意:不要释放tempServiceProvider,因为ossService可能依赖它 // 这里我们接受这个内存开销,因为缓存会减少创建频率 return ossService; } catch (Exception ex) { throw Oops.Oh($"创建OSS服务失败: {ex.Message}"); } } /// /// 验证配置 /// /// 存储提供者配置 /// private Task 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); } /// /// 将SysFileProvider转换为OSSOptions /// /// /// private OSSOptions ConvertToOSSOptions(SysFileProvider provider) { if (provider == null) throw new ArgumentNullException(nameof(provider)); var ossOptions = new OSSOptions { Provider = Enum.Parse(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; } /// /// 清除缓存 /// public void ClearCache() { lock (_lockObject) { _ossServiceCache.Clear(); } } /// /// 释放资源 /// public void Dispose() { if (!_disposed) { lock (_lockObject) { _ossServiceCache.Clear(); } _disposed = true; } } }