【问题标题】:Microsoft dependency injection. How can I get data to a constructor injected class several layers deep微软依赖注入。如何将数据获取到构造函数注入的类深几层
【发布时间】:2019-03-29 15:42:21
【问题描述】:

这是使用 Microsoft.Extensions.DependencyInjection 的 dotNet core 2.2 项目。

我有 3 节课。 A 类在构造函数中使用 B 类。 B类使用C类,C类使用ITenant接口。

ITenant 确定将使用哪个数据库。

示例:

public A(IB b)
public B(IC c)
public C(ITenant t)

它们在注入容器中的设置如下:

services.AddTransient<IA, A>();
services.AddTransient<IB, b>();
services.AddTransient<IC, c>();
services.AddTransient<ITenant , HttpTenant>()>();

在 web 项目中,控制器使用 Class A 作为构造函数参数和容器 createClass A 及其所有依赖项。 ITenant (HttpTenant) 的实现从 HTTP 请求标头中提取租户名称,并从配置文件中获取数据库信息。一切正常。

现在我需要从不涉及 HTTP 请求的 Windows 服务调用它。我有一个响应消息队列的处理程序,A 类是一个构造参数。对于 windows 服务,我有一个不同的 ITenant (WindowServiceTenant):

services.AddTransient<ITenant , WindowServiceTenant>()>();

我不知道如何将租户代码放入 WindowServiceTenant。

  • 租户是在运行时根据从消息队列中读取的值确定的。
  • 当我的处理程序被实例化时,WindowServiceTenant 也被实例化了。
  • 在设置处理程序之前我不认识租户。

我需要获取 WindowServiceTenant 实例的引用并提供租户。或者,此实现 WindowServiceTenant 需要对启动实例化的处理程序的引用。

有什么想法吗?

【问题讨论】:

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


    【解决方案1】:

    基本上有两种解决方案:

    1. 在解析处理程序之前使用所需的值配置 WindowServiceTenant 实例
    2. 通过环境状态传递值,例如可用于线程 (ThreadLocal&lt;T&gt;) 或异步操作 (AsyncLocal&lt;T&gt;) 的值

    第一个选项要求将WindowServiceTenant 注册为Scoped 服务并创建IServiceScope,从中解析WindowServiceTenant 和相应的处理程序:

    // Registration
    services.AddScoped<WindowServiceTenant>();
    services.AddScoped<ITenant>(c => c.GetRequiredService<WindowServiceTenant>());
    
    // Usage
    using (var scope = serviceProvider.CreateScope())
    {
        var services = serviceScope.ServiceProvider;
    
        var tenant = services.GetRequiredService<WindowServiceTenant>();
    
        // Set the right tenant based on a value from the queue
        tenant.SetTenantValue(...);
    
        // Resolve and execute handler
        var handler = services.GetRequiredService(handlerType);
    }
    

    前面的代码清单做了以下事情:

    • 它通过具体类型和接口注册WindowServiceTenant,这样解析WindowServiceTenantITenant 将在单个服务范围内产生相同的实例。这很重要,因为否则会在该作用域实例上设置状态。在同一个服务范围内拥有多个实例显然不会产生正确的结果。
    • 处理您的消息后,您将使用IServiceProvider 上的CreateScope 扩展方法启动一个新的IServiceScope
    • 在该范围内解析WindowServiceTenant。您解决这个具体类型,因为ITenant 抽象将无法设置正确的值(因为这是一个实现细节)
    • 您将队列中的租户值存储在WindowServiceTenant 实例中。由于在服务范围内重复使用同一实例,因此它将被注入到任何依赖于ITenant 的已解析对象图中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-20
      • 2011-02-02
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      • 2018-06-17
      相关资源
      最近更新 更多