【问题标题】:Validate scope for transient inside singleton in .net core?验证.net核心中单例内部瞬态的范围?
【发布时间】:2021-09-05 04:23:18
【问题描述】:

我有 3 个接口(用于单例/作用域/瞬态):

    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)
        {
            
        }
    }

某些服务无法构建(验证时出错 服务描述符 'ServiceType: WebApplication2.ISingleton 生命周期:单例实现类型:WebApplication2.Singlet': 无法从单例中使用范围服务“WebApplication2.IScoped” 'WebApplication2.ISingleton'。)

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

public interface ISingleton
    {
    }

    class Singlet : ISingleton
    {

        public Singlet( Itransient tr)
        {
            
        }
    }

问题:

为什么 .net 核心禁止注入引发异常的较短生命周期(范围)服务,而允许将瞬态注入单例?

【问题讨论】:

  • “为什么 .net 核心禁止注入较短生命周期(范围)的服务引发异常,同时允许将瞬态注入到单例中?” - 因为临时服务的生命周期无关紧要 - 它不是共享资源。
  • @Dai 但它仍然是临时服务的强制依赖。您所说的“无关紧要”是什么意思?那么为什么作用域很重要呢?
  • “它仍然是该瞬态服务的俘获依赖” - 您示例中的瞬态服务没有任何依赖关系。
  • @Dai 我正在重新考虑您所说的:这不是共享资源。....不是。
  • 那么按照同样的逻辑,您是说不允许范围服务请求任何瞬态吗?单线体中的作用域注入的问题在于,相同的实例预计将用于该作用域内的所有内容,但在该作用域之外会创建一个新实例。该要求与单例冲突,因为单例已经创建,它将继续使用前一个范围中的范围实例。对于瞬态,每个服务都有自己的实例,因此永远不会出现范围/共享问题。

标签: c# asp.net-core .net-core dependency-injection


【解决方案1】:

我建议先阅读:When are .NET Core dependency injected instances disposed?

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

为什么 .net 核心禁止注入引发异常的较短生命周期(范围)服务,而允许将瞬态注入单例?

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

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

虽然作用域服务的生命周期比根作用域/根容器的生命周期短,并且根作用域/根容器用于保存单例实例,因此单例不能使用作用域服务 (更重要的是因为子作用域在根作用域的上下文中不存在)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-13
    • 2019-11-03
    • 2019-02-23
    • 2018-01-19
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多