了解 SignalR- 集线器、依赖注入和控制器

Understanding SignalR- Hubs, Dependency Injection, and Controllers

我一直在浏览文档和论坛,试图了解 SignalR,但我很困惑。

我想要实现的是,在聊天应用程序中:将消息存储在 Hub 之外,这样每次用户加入聊天时,他们都可以看到他们加入之前发送的所有消息。

所以看起来外部 class 是做到这一点的方法所以我得到了使用依赖注入的方法

In ChatHub.cs

namespace SignalRChat.Hubs
{
    public class ChatHub: Hub
    {

        public IChatStorage _chatStorage;

        public ChatHub(IChatStorage chatStorage)
        {
            _chatStorage = chatStorage;
        }
    // and so on

我在 ChatHub 中有一个方法可以将消息发送到 chatStorage,但我对如何将所有消息的列表从 chatStorage 发送回 ChatHub,甚至 JavaScript 感到困惑。似乎控制器是执行此操作的方法,但我不确定如何调用控制器的方法:

namespace SignalRChat.Controllers
{
    public class ChatController: Controller
    {
        private IHubContext<ChatHub> _hubContext;

        public ChatController(IHubContext<ChatHub> hubContext)
        {
            _hubContext = hubContext;
        }

        public void Send(List<Message> messages)
        {
            // to do: something where chatStorage calls this method, then this
            // method uses _hubContext.Clients.All.SendAsync 
            // But, how do I even call Send()???
        }
    }
}

从根本上说,我只是不明白如何连接所有东西。 SignalR 真是令人困惑。

我了解简单的服务器 Hub 和客户端 JavaScript 关系是如何工作的。但是,然后通过依赖注入我不明白为什么

public ChatHub(IChatStorage chatStorage)
        {
            _chatStorage = chatStorage;
        }

有效。我没有更改任何代码来表示 new ChatHub(new IChatStorage)。 Microsoft 的文档甚至说 SignalR 仅调用默认的 Hub 构造函数。

在 Startup.cs 中似乎没有任何内容表明我想用新的 chatStorage 调用 ChatHub:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddSignalR();
        services.AddSingleton<IChatStorage, ChatStorage>();
        services.AddSingleton<ChatController>();
    }

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // omitted some default code

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapHub<ChatHub>("/chatHub");
        });
    }

那么第一个问题,它是如何工作的?它如何知道将参数传递给 ChatHub 构造函数?我理解 services.AddSingleton 部分,只是不知道它是如何“连接起来”的。

与控制器相同 class。程序如何知道将 IHubContext 对象传递到其构造函数中?你在哪里指定的?

最后,您将如何进行此设置?目前我正在尝试从 ChatHub->chatStorage->ChatController->ChatHub 进行通信。为此,我尝试在 chatStorage 中传递对 chatController 的引用。

不确定我问的是否清楚。如果有的话,我正在寻找关于这些概念如何协同工作的清晰解释,而不是针对我的代码的特定解决方案。

谢谢!

So first question, how does that work? How does it know to pass an argument to the ChatHub constructor? I understand the services.AddSingleton part, just not how that gets "wired up".

当 SignalR 实例化您的集线器实例时(框架对此进行控制,而您没有),它将解析集线器构造函数中指定的任何依赖项。这是 dependency injection system 的一部分,它是 .NET 的一部分(如评论中所述)。

Same thing with a controller class. How does the program know to pass an IHubContext object into its constructor? Where do you specify that?

相同的想法,但您不必连接 IHubContext,这是 AddSignalR 所做的事情。

Finally, how would you go about making this setup work? Current I'm trying to communicate from ChatHub->chatStorage->ChatController->ChatHub. And to do that I'm trying to pass a reference to chatController in chatStorage.

我不太清楚您希望客户端和服务器与集线器和控制器之间的交互是什么。

What I'm trying to achieve is, in a chat application: store messages outside of the Hub so that each time a user joins the chat, they can see all messages that had been sent before they joined.

回到最初的陈述,我可以问几个澄清的问题:

  • 当用户在聊天室中写消息时,您是在调用集线器还是控制器操作 (REST API)?这将决定您需要在何处注入 IChatStorage 类型。收到消息后,您会将消息存储在 IChatStorage 中。
  • 当用户加入聊天时,他们将调用服务器以检索所有消息。此调用将 return 条消息存储在 IChatStorage 中。

假设您希望对所有内容使用集线器,您可以在集线器上公开方法来完成此操作。如果您想使用来自客户端的 REST API 调用,那么您将使用控制器。