| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- using OnceMi.AspNetCore.OSS;
- using System.Collections.Concurrent;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- 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;
- }
- }
- }
|