我想改进我的应用程序,需要从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);
}
}
有许多有关此主题的SO线程,但我所阅读的一切都会让我将以下代码添加到我的API控制器中:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<TaskHub>();
hubContext.Clients.All.onInsertTask(task);
这里有一些问题。首先,我希望客户端广播调用存在于一个单独的类中,而不是直接从我的API控制器中调用。其次,hubContext
是IHubContext
的实例,而不是IHubCallerConnectionContext
。这意味着我只能访问所有客户端,并且无法像我目前正在做的那样向Caller
和Others
广播不同的响应。有没有一种真正地从C#调用hub方法的方法,并最好能够访问不同的caller选项?理想情况下,我希望能够从我的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);
};
然后,在API控制器中执行适用的CRUD操作后,我从请求中检索了连接ID,然后调用了我的信令中心:
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);
}
我现在只是从我的API控制器调用静态方法,我的仪表板看起来像这样:
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方法中,我有一个条件语句来处理如果hub调用不是从我的应用程序的客户端部分发起的。这将是如果外部应用程序/服务调用了我的API。在这种情况下,SignalR连接和当然"ConnectionId"头值将不存在。尽管如此,在我的情况下,我仍然希望为所有连接的客户端调用onInsertTask
方法,通知他们数据变化。这绝不应该发生,但我只是为了完整性而包含它。