You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core:不使用BuildServiceProvider延迟SQL配置初始化方案

解决方案:避免使用BuildServiceProvider,延迟缓存配置初始化

核心思路

不在ConfigureServices阶段同步拉取SQL配置,而是借助ASP.NET Core的服务延迟解析和托管服务启动钩子,将配置获取逻辑移至应用启动后的预初始化阶段,同时保证缓存服务能正确加载SQL中的配置值。

具体实现步骤

1. 先注册基础依赖服务

首先完成ISqlRepository和FusionCache的基础注册,暂不绑定分布式缓存(Garnet)的具体配置:

public void ConfigureServices(IServiceCollection services)
{
    // 注册SQL仓储(保持原有的Scoped生命周期)
    services.AddScoped<ISqlRepository, SqlRepository>();
    
    // 注册FusionCache核心服务,先设置通用默认配置
    services.AddFusionCache()
        .WithDefaultEntryOptions(options =>
        {
            options.Duration = TimeSpan.FromMinutes(5); // 临时默认值,后续会被SQL配置覆盖
            options.IsFailSafeEnabled = true;
        });
    
    // 注册Web API基础服务
    services.AddControllers();
}

2. 编写缓存配置初始化托管服务

创建单例托管服务,负责在应用启动时异步拉取SQL配置,并完成FusionCache与Garnet的绑定:

public class CacheConfigInitializer : IHostedService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IFusionCache _fusionCache;
    private readonly SemaphoreSlim _initLock = new SemaphoreSlim(0, 1);

    public CacheConfigInitializer(IServiceProvider serviceProvider, IFusionCache fusionCache)
    {
        _serviceProvider = serviceProvider;
        _fusionCache = fusionCache;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        try
        {
            // 创建Scope解析Scoped类型的ISqlRepository
            using var scope = _serviceProvider.CreateScope();
            var sqlRepo = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
            
            // 异步从SQL拉取缓存配置
            var configParamStore = await sqlRepo.GetConfigParamStoreAsync(cancellationToken);
            
            // 初始化Garnet分布式缓存配置
            var garnetOptions = new GarnetCacheOptions
            {
                Configuration = configParamStore.GarnetConnectionString,
                InstanceName = configParamStore.GarnetInstanceName
            };
            
            // 将Garnet挂载为FusionCache的L2分布式缓存
            _fusionCache.WithDistributedCache(new GarnetCache(garnetOptions));
            
            // 用SQL配置覆盖FusionCache全局默认值
            _fusionCache.SetDefaultEntryOptions(options =>
            {
                options.Duration = TimeSpan.FromSeconds(configParamStore.CacheDurationSeconds);
                options.IsFailSafeEnabled = configParamStore.EnableFailSafe;
            });
        }
        finally
        {
            _initLock.Release(); // 标记初始化完成
        }
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

    // 对外提供等待初始化完成的方法,供业务代码调用
    public async Task WaitForInitCompleteAsync(CancellationToken cancellationToken = default)
    {
        await _initLock.WaitAsync(cancellationToken);
        _initLock.Release(); // 释放锁,让后续请求无需等待
    }
}

3. 注册初始化服务

在ConfigureServices中添加托管服务注册,确保应用启动时自动执行配置初始化:

public void ConfigureServices(IServiceCollection services)
{
    // ... 之前的服务注册代码 ...
    
    // 注册缓存配置初始化托管服务
    services.AddHostedService<CacheConfigInitializer>();
}

4. 处理缓存未初始化的边界场景

在业务代码中,先等待缓存初始化完成再使用FusionCache,避免空配置导致的错误:

public class BusinessService
{
    private readonly IFusionCache _fusionCache;
    private readonly CacheConfigInitializer _configInitializer;

    public BusinessService(IFusionCache fusionCache, CacheConfigInitializer configInitializer)
    {
        _fusionCache = fusionCache;
        _configInitializer = configInitializer;
    }

    public async Task<DataModel> GetDataAsync(int id)
    {
        // 等待缓存配置初始化完成
        await _configInitializer.WaitForInitCompleteAsync();
        
        return await _fusionCache.GetOrSetAsync(
            cacheKey: $"data_{id}",
            factory: async () => await FetchDataFromDbAsync(id),
            options: opts => opts.Duration = TimeSpan.FromMinutes(10)
        );
    }
}

方案优势

  • 彻底规避BuildServiceProvider带来的服务生命周期不一致、内存泄漏等风险
  • 利用IHostedService异步执行初始化,不阻塞Web API的启动流程
  • 通过Scope正确解析Scoped类型的仓储服务,符合DI设计规范
  • 加锁逻辑确保业务代码不会在缓存未就绪时执行,避免异常

内容的提问来源于stack exchange,提问作者Creative Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:43:14