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

ASP.NET Core 6 MVC启动时缓存数据库数据遇依赖注入错误求助

问题分析与解决方案

错误原因

你当前的问题出在直接使用根IServiceProvider获取Scoped生命周期的服务:

  • IAccountManagerRepository通常注册为Scoped(与请求生命周期绑定),而根服务容器不负责管理Scoped服务的创建与释放,直接调用GetService会导致解析失败。
  • IStartupFilter的执行时机是在应用管道构建阶段,此时服务容器尚未完全初始化,无法正确处理Scoped服务的依赖链。

解决方案一:修改中间件以支持请求级服务解析

如果你的需求是每个请求都执行数据获取与缓存更新,修改中间件的Invoke方法,通过HttpContext.RequestServices(请求级服务提供者)来获取服务:

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    // 移除IServiceProvider注入,直接在Invoke中使用HttpContext的服务
    public RequestSetOptionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        Console.WriteLine("test 12312 1 23 123 1 23 12");
        
        // 创建请求级Scope,确保Scoped服务被正确管理
        using var scope = httpContext.RequestServices.CreateScope();
        var cont = scope.ServiceProvider.GetRequiredService<IAccountManagerRepository>();
        var accountManagers = cont.GetAccountManagersThirdPartyNotTrueWithSelection();

        // 这里添加缓存逻辑,比如存入IMemoryCache
        var cache = scope.ServiceProvider.GetRequiredService<IMemoryCache>();
        cache.Set("AccountManagers", accountManagers);

        await _next(httpContext);
    }
}

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

解决方案二:用IHostedService实现启动时一次性预加载缓存

如果你的需求是应用启动时仅执行一次数据获取并缓存,IStartupFilter不是合适的选择,应该使用IHostedService(后台服务),它会在应用完全启动后执行:

1. 实现后台服务

public class CachePreloadHostedService : IHostedService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly IMemoryCache _cache;

    public CachePreloadHostedService(IServiceProvider serviceProvider, IMemoryCache cache)
    {
        _serviceProvider = serviceProvider;
        _cache = cache;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // 创建Scope解析Scoped仓储服务
        using var scope = _serviceProvider.CreateScope();
        var repo = scope.ServiceProvider.GetRequiredService<IAccountManagerRepository>();
        
        // 建议使用异步方法避免阻塞启动
        var accountManagers = await repo.GetAccountManagersThirdPartyNotTrueWithSelectionAsync();
        
        // 将数据存入缓存,设置过期时间
        _cache.Set("AccountManagers", accountManagers, TimeSpan.FromHours(1));
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

2. 在Program.cs注册服务

// 注册缓存服务(如果还没注册)
builder.Services.AddMemoryCache();
// 注册后台服务
builder.Services.AddHostedService<CachePreloadHostedService>();

关键注意事项

  • 永远不要用根IServiceProvider获取Scoped服务,必须通过CreateScope创建请求级或临时Scope来解析。
  • 区分启动时一次性执行和每个请求执行的场景,选择对应的实现方式:IHostedService适合前者,中间件适合后者。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:55:02