SignalR: How to truly call a hub#39;s method from the server / C#(SignalR:如何从服务器真正调用集线器的方法/C#)
问题描述
我正在努力改进我的应用程序,它需要从C#而不是javascript调用集线器。在我的应用程序中添加任务的当前工作流为:
- 调用API将数据添加到数据库
- 将新记录返回到AngularJS控制器
- 从控制器调用集线器的方法
- 集线器适当地向客户端广播呼叫
我想做的是绕过从我的AngularJS控制器调用集线器的方法,而直接从我的API控制器方法调用它。
这是我的集线器当前的样子:
public class TaskHub : Hub
{
public void InsertTask(TaskViewModel task)
{
Clients.Caller.onInsertTask(task, false);
Clients.Others.onInsertTask(task, true);
}
}
这个主题上有很多这样的主题,但我读到的所有内容都会让我将以下代码添加到我的API控制器中:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<TaskHub>();
hubContext.Clients.All.onInsertTask(task);
这有许多问题。首先,也是最重要的,我希望客户端广播调用存在于单个类中,而不是直接从我的API控制器调用。其次,hubContext
是IHubContext
的实例,而不是IHubCallerConnectionContext
的实例。这意味着我只能访问所有客户端,无法像我当前那样广播对Caller
和Others
的不同响应。
有没有办法从C#真正调用集线器的方法,并且理想情况下可以访问不同的调用方选项?理想情况下,我能够从我的API控制器(或者更好的情况是,使用DI的解决方案)执行如下所示的简单操作:
var taskHub = new TaskHub();
taskHub.InsertTask(task);
提前感谢。
解决方案
对于后人,我认为我应该按照Wasp的建议包括我的完整解决方案。
首先,我修改了javascript(AngularJS)服务,将SignalR连接ID包括在API调用的自定义请求头中,在本例中为INSERT:
var addTask = function (task) {
var config = {
headers: { 'ConnectionId': connection.id }
};
return $http.post('/api/tasks', task, config);
};
然后,在执行了适用的CRUD操作之后,我在API控制器中从请求中检索了连接ID,然后调用了My Hub:
public HttpResponseMessage Post(HttpRequestMessage request, [FromBody]TaskViewModel task)
{
var viewModel = taskAdapter.AddTask(task);
var connectionId = request.Headers.GetValues("ConnectionId").FirstOrDefault();
TaskHub.InsertTask(viewModel, connectionId);
return request.CreateResponse(HttpStatusCode.OK, viewModel);
}
我的集线器如下所示,我现在只使用从接口控制器调用的静电方法:
public class TaskHub : Hub
{
private static IHubContext context = GlobalHost.ConnectionManager.GetHubContext<TaskHub>();
public static void InsertTask(TaskViewModel task, string connectionId)
{
if (!String.IsNullOrEmpty(connectionId))
{
context.Clients.Client(connectionId).onInsertTask(task, false);
context.Clients.AllExcept(connectionId).onInsertTask(task, true);
}
else
{
context.Clients.All.onInsertTask(task, true);
}
}
}
如您所见,如果集线器调用不是从应用程序的客户端部分发起的,我在Hub方法中有一个条件语句来处理。这是在外部应用程序/服务调用My API的情况下进行的。在这种情况下,SignalR连接当然也不存在"ConnectionId"头值。不过,在我的示例中,我仍然希望为所有连接的客户端调用onInsertTask
方法,以通知它们数据更改。这不应该发生,但我只是出于完整性考虑将其包括在内。
推荐答案
为了真正地调用您所调用的集线器方法,您必须连接到它,并通过该连接进行调用。通过调用不同的东西(您的API),您不能进行这种类型的调用,因此您必须求助于服务器发起的广播功能,该功能本质上无法知道Caller
是什么,因为没有SignalR的调用方。
也就是说,如果您的客户端在执行调用时调用API(无论是Javascript还是C#)已经连接到集线器,则始终可以使用集线器连接的connectionId
修饰对API的调用(按查询字符串、按标头等)。如果您的API收到该信息,则可以使用Caller
Caller
API
Clients.Client(connectionId)
它可以对Others
使用
Clients.AllExcept(connectionId)
在IHubContext
实例上。检查official docs。
然后您可以按照DDan的建议,以一种方便的集中方式封装IHubContext
用法,甚至对其稍加调整,使其轻松兼容DI。
这篇关于SignalR:如何从服务器真正调用集线器的方法/C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:SignalR:如何从服务器真正调用集线器的方法/C#
基础教程推荐
- 如何激活MC67中的红灯 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 将 XML 转换为通用列表 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- c# Math.Sqrt 实现 2022-01-01