验证 .net 核心中单例内部瞬态的范围?

Validate scope for transient inside singleton in .net core?

我有 3 个接口(singleton/scoped/transient):

    public interface ISingleton
    {
    }

    class Singlet : ISingleton
    {
    }

    public interface IScoped
    {
    }

    class Scoped : IScoped
    {
    }


    public interface Itransient
    {
    }

    class Transient : Itransient
    {
    }

我将它们注册为:

 services.AddScoped<IScoped, Scoped>();
 services.AddTransient<Itransient, Transient>();
 services.AddSingleton<ISingleton, Singlet>();

如果我尝试向 singleton 注入作用域服务,我应该(并且确实)得到一个异常(我知道这样做的原因):

    public interface ISingleton
    {
    }

    class Singlet : ISingleton
    {

        public Singlet( IScoped sc)
        {
            
        }
    }

Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: WebApplication2.ISingleton Lifetime: Singleton ImplementationType: WebApplication2.Singlet': Cannot consume scoped service 'WebApplication2.IScoped' from singleton 'WebApplication2.ISingleton'.)

但是如果我尝试注入 transient ,我不会得到异常 :

public interface ISingleton
    {
    }

    class Singlet : ISingleton
    {

        public Singlet( Itransient tr)
        {
            
        }
    }

问题:

为什么 .net core 禁止注入较短生命周期(作用域)服务引发异常,同时允许将瞬态注入单例?

我建议先阅读这篇文章:

(前言:我的回答假设服务实现本身从不处理任何注入的服务。)

Why does .net core forbids injecting a shorter lifetime (scoped) services raising an exception, while allowing transient to be injected to a singleton?

  • 瞬态服务的生命周期与其在其中实例化的容器相同。
    • 瞬态服务可以在root-scope/root-container(单例所在的位置)或范围容器内实例化。
    • 注入单例的新瞬态服务实例的生命周期是单例容器(通常是根容器或根范围)的生命周期。
      • 也就是说,临时实例只有在根容器被销毁时才会被销毁,通常是在应用程序关闭期间(IHost.Dispose())
    • 注入作用域服务的新瞬态服务实例的生命周期是该作用域容器的生命周期。
      • 也就是说,瞬态实例只有在释放作用域时才会被释放(在 ASP.NET Core 中,即在 HTTP 请求生命周期结束时)。
    • 注入另一个瞬态服务的新瞬态服务的生命周期是DI提供者构造的最终消费者的生命周期。

简而言之:瞬态服务的生命周期与其注入的服务相同——不长也不短。这就是它被允许的原因。

虽然范围服务的生命周期比root-scope/root-container的生命周期短,并且root-scope/root-container用于保存单例实例,因此范围服务不能被单例使用(更重要的是,这是因为子作用域 在根作用域的上下文中不存在