Я пытаюсь улучшить свое приложение, которое потребует вызова хаба из С# вместо 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
, как я сейчас делаю.
Есть ли способ по-настоящему вызвать метод хаба из С# и, в идеале, иметь доступ к различным параметрам вызова? В идеале я мог бы сделать что-то так же просто, как следующее из моего контроллера API (или, еще лучше, решение с DI):
var taskHub = new TaskHub();
taskHub.InsertTask(task);
Спасибо заранее.
Решение
Для потомков я думал, что включу свое полное решение в соответствии с предложением Wasp.
Сначала я изменил мою службу javascript (AngularJS), чтобы включить идентификатор соединения SignalR в заголовок настраиваемого запроса для вызова API, в этом случае INSERT:
var addTask = function (task) {
var config = {
headers: { 'ConnectionId': connection.id }
};
return $http.post('/api/tasks', task, config);
};
Затем я получил идентификатор соединения из запроса в моем контроллере API после выполнения применимой операции CRUD, а затем вызвал мой концентратор:
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);
}
}
}
Как вы можете видеть, у меня есть условный оператор в моем методе хаба для обработки, если вызов хаба не был инициирован с клиентской части моего приложения. Это было бы, если внешнее приложение/служба называли мой API. В такой ситуации соединение SignalR и, конечно, значение "ConnectionId" не существует. В моем случае, тем не менее, мне все равно хотелось бы вызвать метод onInsertTask
для всех подключенных клиентов, который информирует их об изменении данных. Это никогда не должно происходить, но я просто включил его для полноты.