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

在单例服务中注入ITokenAcquisition在Development环境下失效

问题解答:后台服务中使用ITokenAcquisition的异常分析

1. 是否允许在后台服务中注入ITokenAcquisition?

不建议直接注入。ITokenAcquisition默认是Scoped生命周期的服务,而后台服务(IHostedService)属于Singleton生命周期。在.NET依赖注入系统中,单例服务不能直接依赖Scoped服务——这会导致Scoped服务被单例长期持有,失去其“作用域内唯一”的特性,可能引发线程安全问题或状态污染。

正确的做法是通过注入IServiceProvider,在需要使用ITokenAcquisition时临时创建作用域,获取Scoped实例:

public class QueuedHostedService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;

    public QueuedHostedService(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    private async Task BackgroundProcessing(CancellationToken stoppingToken)
    {
        // 创建临时作用域
        using var scope = _serviceProvider.CreateScope();
        var tokenAcquisition = scope.ServiceProvider.GetRequiredService<ITokenAcquisition>();
        
        // 在作用域内使用服务
        var token = await tokenAcquisition.GetAccessTokenForAppAsync("api://xxxxx-5a7f-430e-8ea1-6e133055990e/.default");
        
        while (!stoppingToken.IsCancellationRequested)
        {
            Console.WriteLine("Executing...");
            await Task.Delay(1000, stoppingToken);
        }
    }
}

2. 为何代码在Test/Production模式下可行,但Development模式下失效?

这是因为.NET在不同环境下的服务验证策略不同:

  • Development环境:默认启用ValidateScopes和ValidateOnBuild选项,启动时会严格检查服务的生命周期依赖关系。当检测到单例依赖Scoped服务时,直接抛出异常阻止应用启动。
  • Production/Test环境:默认关闭ValidateScopes验证,不会主动检查这种不合法的依赖,所以应用能启动。但这只是“表面可行”,实际上潜在的生命周期问题依然存在,可能在运行时引发难以排查的BUG。

如果需要统一各环境的验证行为,可以在Program.cs中显式配置:

var builder = WebApplication.CreateBuilder(args);
// 强制开启服务验证(所有环境)
builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;
    options.ValidateOnBuild = true;
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:55:06