【问题标题】:How to receive IHubContext out of Dependency Injected classes?如何从依赖注入类中接收 IHubContext?
【发布时间】:2019-04-23 11:10:16
【问题描述】:

我想在发生某些事件时使用 SignalR 从 Service A 发送消息(例如,收到来自 Service B 的消息)。 因此需要从某种处理程序调用集线器方法,该处理程序不是使用依赖注入构造的。我该怎么做?

到目前为止,我尝试并阅读了以下内容:

  1. 我可以将上下文注入控制器并将其引导至我的处理程序。我可能可以这样做,但是将集线器上下文从顶部(控制器类)传递到底部(处理程序类)并不是最好的方法,这会给不应该知道这个上下文的类添加很多依赖项,所以我希望避免这种情况。
  2. 我可以注入我的 IHubContext in "any" class,但问题是,如何在我的处理程序上获取该类的实例?
  3. 向具有注入上下文的类添加静态方法!?好吧,这在您拥有 1 个客户端之前有效,因为新客户端的静态属性将被覆盖。

所以我无法想象,处理程序如何使用依赖注入的 IHubContext。

可能有人以前做过,并且有一个如何将上下文真正注入 any 类的示例。

提前感谢您,如有必要,我们将提供任何其他信息。

【问题讨论】:

  • 你在什么时候构建你的处理程序?我想,处理程序不是起点,否则,您可以使用 AddSingleton 或其他 Add* 方法将其添加到 Startup 类中的 DI。然后使用 ServiceProvider 解决它,这将自动解决我的处理程序的 IHubContext 依赖关系。您能否详细说明更多代码?
  • @ShahzadHassan 经过一番思考。是的,处理程序不是入口点。每次服务启动时创建一次处理程序,因此多个客户端可以连接到该服务并通过该处理程序。另一方面,根据method call 创建一个集线器实例。我想我应该从问题中删除带有“理想解决方案”的那一行。
  • 恐怕在这种情况下选择是有限的。 DI从上到下工作,但首先解决内部依赖关系,所以如果A对B有依赖关系,B对C有依赖关系。它会先解决B的依赖关系,然后再去A。我猜,你是新的在控制器内部的某个位置启动处理程序?为什么不为处理程序实现一个接口并将其注入控制器?这样它将由 DI 解决
  • @ShahzadHassan 不,我不是在控制器内新建处理程序。基本上,只有在服务重新启动时才会重建处理程序。另外,我无法为处理程序实现和注入接口,因为处理程序有一些其他依赖项不是由 DI 构造的。

标签: asp.net-core signalr signalr-hub asp.net-core-signalr


【解决方案1】:

回答 1

这是一种可能的解决方案。实现工厂模式。创建一个知道如何创建处理程序的工厂。在工厂中注入 IHubContext。您可以这样使用几种方法:

  1. 通过传入IHubContext构造Handler
  2. 在Handler中创建公共属性并设置IHubContext
  3. 在Handler中创建方法,将IHubContext作为参数传递

您可以决定哪种方法适合您。通过 DI 将该工厂注入到控制器中,并使用工厂方法获取处理程序。这样你就不会暴露 IHubContext。请看下面的代码

public interface IHandlerFactory
{
   Handler CreateHandler();
}

public class HandlerFactory : IHandlerFactory
{
    private IHubContext _hubContext;

    public HandlerFactory(IHubContext context)
    {
        _hubContext = context;
    }
    public Handler CreateHandler()
    {
        return new Handler(param1, param2, _context);
    }    
}

然后在入口点,controller/service,通过DI注入工厂

public class MyController : Controller
{
    private Handler _handler;

    public MyController(IHandlerFactory factory)
    {
        _handler = factory.CreateHandler();
    }
}

然后您可以在其他方法中使用该 _handler。我希望这会有所帮助。

答案 2

如果可能的话,另一个可能的解决方案是使用 IHostedService。请参阅由 David Fowler here 提供的 GitHub issue 的解决方案,我认为这与您的方案有些相关。

【讨论】:

  • 实现工厂意味着 Handler 和 Hub 具有相同的范围。但他们不是。 Hub 在每个方法调用上构建。即使客户端调用一个方法,Hub 也会被构造 3 次(OnConnected 和 OnDisconnected + 调用方法)。想象一下,如果我在每次调用时都构建 Handler 并且不需要因为处理程序始终相同,那么资源问题将有多大,唯一的区别是其中的上下文。第二个答案很有趣。我会仔细看看,但无论如何,可能无法避免创建某种包含上下文的容器。
  • 如果处理程序始终相同,您可以在工厂内将其创建为单例。您将无法以这种方式将新的 HubContext 传递给构造函数。但是,您可以选择选项 2 或 3。确保以线程安全的方式实现单例。是的,你需要某种 IoC 容器在某处做一些 DI。让我知道答案 2 是否更适合您。
  • Shahzad,你的评论和帮助真的给了我一个提示,如何解决这个问题。我使用了 DI,但从另一个角度来看。稍后我将添加我的评论并进行详细解释。再次感谢您!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 2023-04-06
  • 2017-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多