依赖注入作用域为瞬态,然后瞬态为单例

Posted

技术标签:

【中文标题】依赖注入作用域为瞬态,然后瞬态为单例【英文标题】:Dependency injection Scoped into Transient and then Transient into Singleton 【发布时间】:2021-01-14 20:04:06 【问题描述】:

我有一个 scoped Context 正在通过方法从 transient 服务访问。 这个transient 服务被注入到singleton 服务中。

我的 scoped Context 会变成单例还是保持范围?

public class Context : IContext

    public string CorrelationId  get; set; 

    public Context(string id)
    
        CorrelationId = id;
    

上下文访问器:

internal class RequestContextRegistrator : IRequestContextRegistrator

    private IContext context;

    public IContext RegisterContext(IContext context)
    
        this.context = context;

        return context;
    

    public IContext Get()
    
        return context ?? new Context()
        
            CorrelationId = context.CorrelationId
        ;
    

单例对象:

public class QueueSender<TCommand> 

    private readonly IRequestContextRegistrator provider;

    public QueueSender(IRequestContextRegistrator provider)
    
       this.provider = provider;
    

    public async Task Send(TCommand command)
    
        var context = provider.Get();

        var message = PrepareServiceBusMessage(command, userAgent, context?.CorrelationId);

    

整个想法是能够传递特定“请求”独有的上下文 ID。请求不是来自dotnet 控制器,它来自队列接收器类。

或者解释一下,这种到单例的转换对于依赖注入树的深度有多大。

【问题讨论】:

【参考方案1】:

我的作用域上下文会变成单例还是保持作用域?

它将保持范围。

您的单例实例将注入一个RequestContextRegistrator,而这又将注入一个Context;这个 Context 实例将一直存在,直到您的应用程序终止,因为单例将保留其引用,但是,任何其他需要 IContext 的类都将注入一个 new Context

【讨论】:

那最终不会导致内存泄漏吗? 只有在卸载包含AppDomain 时,才会对单例及其依赖项进行垃圾回收;因为您正在创建一个单例,所以您明确要求这种行为。仅涉及 3 个实例,因此不会导致内存问题。 每个队列消息都会有一个新的context,如果服务消耗了 1.000.000 条消息不是问题吗? 什么是队列消息?您尚未共享任何其他将 IContext 作为依赖项的类。 QueueSender 发送队列消息。【参考方案2】:

不要从单例解析范围服务。可能会导致服务在处理后续请求时状态不正确。没关系:

从范围服务或临时服务中解析单例服务。 从另一个范围服务或临时服务中解析一个范围服务。

请查看此链接Service lifetime

【讨论】:

以上是关于依赖注入作用域为瞬态,然后瞬态为单例的主要内容,如果未能解决你的问题,请参考以下文章

angular 2 瞬态提供程序而不是单例

Blazor 中的依赖注入与 Razor 组件

在快速测试用例中为单例目标 c 类注入依赖项

dotnet 核心中的 Dbcontext 对象瞬态

使用单例数据源的瞬态和作用域服务

将 Dbcontext 配置为瞬态