Клиент не получает сообщение SignalR от контроллера

Я пытаюсь отправить сообщение от контроллера группе клиентов с помощью SignalR. Когда в одном из моих контроллеров происходит событие, мне нужно отправить сообщение с помощью концентратора сигналов, чтобы оно отображалось как предупреждение на экранах моих клиентов. Я знаю, что здесь было задано много вопросов, и я прочитал и попробовал многие из них. Поскольку я новичок в SignalR, некоторые из них даже помогли мне все наладить. На данный момент вроде все на своих местах. Клиенты могут подключаться к концентратору и присоединяться к группам, а контроллер может вызывать методы из концентратора. Но клиент никогда не получает сообщение, и я не могу понять почему. Я подозреваю, что метод концентратора, вызываемый контроллером, не «видит» клиентов, но я не могу понять, что не так.

Код хаба:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

[HubName("myHub")]
public class MyHub : Hub
{
    private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
    public void Notify(string groupName, string message)
    {
        Clients.Group(groupName).displayNotification(message);
    }

    public static void Static_Notify(string groupName, string message)
    {
        var toto = UserHandler.ConnectedIds.Count();
        hubContext.Clients.Group(groupName).displayNotification(message);
        hubContext.Clients.All.displayNotification(message);//for testing purpose
    }

    public Task JoinGroup(string groupName)
    {
        return Groups.Add(Context.ConnectionId, groupName);
    }

    public Task LeaveGroup(string groupName)
    {
        return Groups.Remove(Context.ConnectionId, groupName);
    }

    public override Task OnConnected()
    {
        UserHandler.ConnectedIds.Add(Context.ConnectionId);
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool StopCalled)
    {
        UserHandler.ConnectedIds.Remove(Context.ConnectionId);
        return base.OnDisconnected(StopCalled);
    }
}

Вот звонок от моего контроллера:

//(For simplification and readability I define here variables actually obtained by treating some data )
//I already checked that problem did not come from missing data here
string groupName = "theGroupName";
string message = "My beautifull message.";

//prepare signalR call
var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();

//Following commented lines are different attempts made based on exemples and answers I found here and on others sites.
//The uncommented one is the one in use at the moment and is also based on an answer (from SO i think)

//context.Clients.Group(_userEmail).displayNotification(message);
//context.Clients.Group(_userEmail).Notify(_userEmail,message);
  MyHub.Static_Notify(_userEmail, message);

А вот и клиентский код:

$(document).ready(function () {
    var userGroup = 'theGroupName';
    $.connection.hub.url = 'http://localhost/SignalRHost/signalr';
    var theHub = $.connection.myHub;
    console.log($.connection)
    console.log($.connection.myHub)

    theHub.client.displayNotification = function (message) {
        console.log('display message');
        alert(message);
    };

    $.connection.hub.start()
        .done(function () {
            theHub.server.joinGroup(userGroup);
            console.log("myHub hub started : " + $.connection.hub.id)
            console.log(theHub)
        })
        .fail(function () {
            console.log('myHub hub failed to connect')
        });

});

Пожалуйста, помогите мне понять, какую логику я не понял или какую ошибку мне не хватает.

РЕДАКТИРОВАТЬ:

Чтобы ответить на комментарий Алиссона: The Startup.cs, который я забыл показать

public void Configuration(IAppBuilder app)
    {
        app.Map("/signalr", map =>
        {
            map.UseCors(CorsOptions.AllowAll);
            var hubConfiguration = new HubConfiguration { };
            map.RunSignalR();
        });
    }

Я тоже забыл упомянуть важные вещи:

  • Контроллер, концентратор и клиент - это 3 разных проекта (из-за глобальной архитектуры приложения мне пришлось разделить логику концентратора). Все они находятся на моем локальном хосте IIS, но на разных портах.
  • Я установил точки останова для событий «OnConnected» и «onDiconnected», и клиент подключается и отключается нормально.

person Grey    schedule 19.12.2017    source источник
comment
Ваш проект MVC выполняется на вашем локальном хосте? Я имею в виду, вы опубликовали свой проект в локальном IIS или отлаживаете его с помощью IIS Express из Visual Studio? Не могли бы вы рассказать, как вы настроили SignalR в своем Startup.cs файле?   -  person Alisson    schedule 19.12.2017
comment
Спасибо @Alisson за указание важной информации, которую я забыл упомянуть. Я ответил на ваши вопросы внизу поста.   -  person Grey    schedule 19.12.2017
comment
Если контроллеры и хабы в разных проектах, значит, не работает. У вас есть два проекта, выступающих в качестве сервера SignalR: проект контроллера и проект концентратора (даже если вы используете один и тот же класс концентратора в обоих проектах). Когда вы вызываете MyHub.Static_Notify(_userEmail, message); в своем контроллере, ваш концентратор вызывает клиентов, подключенных к проекту контроллеров, но ваши клиенты фактически подключены к проекту SignalRHost. Вы должны либо использовать один уникальный проект для концентраторов и контроллеров, либо убедиться, что ваш контроллер вызывает концентратор в проекте SignalRHost.   -  person Alisson    schedule 19.12.2017
comment
Cna вы добавите console.log(theHub.client) и добавите результат к вашему вопросу?   -  person Hackerman    schedule 19.12.2017
comment
Большое спасибо @Alisson, я буду работать над способом вызова хаба в правом контроллере. Если бы я мог принять комментарий в качестве ответа, я бы принял ваш.   -  person Grey    schedule 19.12.2017
comment
Нет, моего комментария было недостаточно, чтобы считаться реальным ответом. Я ответил с более подробной информацией и образцом кода, надеюсь, это вам поможет. Дайте мне знать, если вы все еще не можете это сделать.   -  person Alisson    schedule 19.12.2017


Ответы (1)


Вам просто нужно одно приложение, которое будет выступать в качестве сервера, в вашем случае это должен быть проект SIgnalRHost. Ваш проект контроллера должен быть клиентом сервера, поэтому ему просто нужен этот пакет:

Install-Package Microsoft.AspNet.SignalR.Client 

Вашему проекту контроллера на самом деле не нужно ссылаться на проект, содержащий класс концентратора. В вашем контроллере вы будете использовать клиент C # SignalR для подключения к серверу (как в клиенте javascript), присоединитесь к группе и вызовите метод концентратора:

var hubConnection = new HubConnection("http://localhost/SignalRHost/signalr");
IHubProxy myHub = hubConnection.CreateHubProxy("MyHub");
await hubConnection.Start();
myHub.Invoke("JoinGroup", "theGroupName");
myHub.Invoke("Notify", "theGroupName", "My beautifull message.");

... наконец, тебе это Static_Notify совсем не нужно.

Поскольку вы передаете имя группы в качестве параметра метода Notify, вам действительно не нужно присоединяться к группе с вашего контроллера. Вам понадобится только в том случае, если вы пытаетесь отправить сообщение той же группе, к которой был подключен контроллер (тогда вам больше не нужно будет передавать имя группы в качестве параметра).

Справочник клиента SignalR C #.

person Alisson    schedule 19.12.2017
comment
Большое спасибо, я полностью пропустил клиентскую часть C #. Работает отлично. - person Grey; 20.12.2017