Как получить сообщение для конкретного пользователя с помощью SignalR c # MVC?

#c# #asp.net-mvc #signalr #signalr.client

#c# #asp.net-mvc #signalr #signalr.client

Вопрос:

У меня есть приложение MVC.

Я реализовал SingalR для получения уведомлений в реальном времени, но как получать уведомления только для конкретного пользователя.

NotificationSend.cs

 public class NotificationSend : Hub
{
    private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationSend>();
    public static ConcurrentDictionary<string, MyUserType> MyUsers = new ConcurrentDictionary<string, MyUserType>();

    public override Task OnConnected()
    {
        MyUsers.TryAdd(Context.ConnectionId, new MyUserType() { ConnectionId = Context.ConnectionId });
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        MyUserType garbage;

        MyUsers.TryRemove(Context.ConnectionId, out garbage);

        return base.OnDisconnected(stopCalled);
    }

    public static void SendToUser(string messageText)
    {
        hubContext.Clients.Client(MyUsers.Keys.ToList().FirstOrDefault()).Notification(messageText);
    }

    public static void StopLoader(string messageText)
    {
        hubContext.Clients.Client(MyUsers.Keys.ToList().FirstOrDefault()).Stoploader(messageText);
    }
}
public class MyUserType
{
    public string ConnectionId { get; set; }
}
  

HomeController.cs

 public class HomeController : Controller
    {

    public async Task<ActionResult> SaveData()
        {
         foreach (var mydata in DataList)
                {
                   // save data code and show below message on UI
                   NotificationSend.SendToUser(mydata.Name   ": Data saved");
  

Я могу получать уведомления в пользовательском интерфейсе отлично, но проблема в

Если пользователь A использует свой собственный компьютер и свой логин, он должен получать только свое уведомление, я знаю, что URL веб-приложения такой же.

для этого я вношу нижеприведенные изменения, но после этого изменения не видно никаких уведомлений.

 string UserID = User.Identity.Name;
hubContext.Clients.User(UserID).Notification(mydata.Name   ": Data saved");
  

Layout.js

 $(function () {
            var notification = $.connection.notificationSend;
            console.log(notification);
            notification.client.Notification = function (Count) {
                $('#liveupdate').empty();
                $('#liveupdate').show();
                $('#liveupdate').append(Count);
            };
            $.connection.hub.start().done(function () {
                var connectionId = $.connection.hub.id;
                console.log("Connected Successfully");
            }).fail(function (response) {
                console.log("not connected"   response);
            });
        });
  

Комментарии:

1. для отправки сообщения обратно клиенту серверу необходимо знать информацию о подключении к сокету, и при использовании того же экземпляра браузера результирующий адрес остается тем же, я думаю, именно поэтому сообщение отправляется на все вкладки, SignalR работает нормально

2. где вы регистрируете отдельных пользователей в SignalR ? и что делает эта строка hubContext.Clients.All.Notification(mydata.Name ": Data saved");

3. реализовали ли вы OnConnected() и OnDisconnected() в своем Hub ?

4. для начала создайте статический класс для сохранения HubContext экземпляра в памяти и добавьте группу в hub на основе идентификатора пользователя или электронной почты, которые могли бы однозначно идентифицировать его / ее, затем используйте контекст для отправки уведомления этой конкретной группе, которая будет содержать только этого пользователя

5. Я добавил свой ответ, посмотрите, имеет ли это смысл

Ответ №1:

Добавьте статический класс, его экземпляр будет создан один раз и сохранит информацию в памяти, как экземпляр context

 public static class NotificationsResourceHandler
{
    private static readonly IHubContext myContext;       
    public static Dictionary<string, string> Groups;



    static NotificationsResourceHandler()
    {
        myContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();   
        Groups = new Dictionary<string, string>();
    }

    public static void BroadcastNotification(dynamic model, NotificationType notificationType, string userName)
    {
        myContext.Clients.Group(userName).PushNotification(new { Data = model, Type = notificationType.ToString() });
    }
}
  

и в вашем хабе

 [HubName("yourHub")]
public class MyHub : Hub
{
    public override Task OnConnected()
    {
        var userEmail = Context.QueryString["useremail"]?.ToLower();
        if (userEmail == null) throw new Exception("Unable to Connect to Signalr hub");

        if (NotificationsResourceHandler.Groups.All(x => x.Value != userEmail))
        {
            NotificationsResourceHandler.Groups.Add(Context.ConnectionId, userEmail);
            Groups.Add(Context.ConnectionId, userEmail);
        }
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        NotificationsResourceHandler.Groups.Remove(Context.ConnectionId);
        Clients.All.removeConnection(Context.ConnectionId);

        return base.OnDisconnected(stopCalled);
    }
}
  

Уведомление будет отправлено отдельным группам, для вашей проблемы вы должны создать отдельную группу для каждого пользователя, как предусмотрено в коде.

Комментарии:

1. спасибо за ваши усилия, но я могу изменить полную реализацию прямо сейчас, есть ли шанс, что мы сможем внести изменения в мой текущий код?

2. что ж, я могу попробовать, у меня работало это решение, поэтому я его опубликовал, я могу попытаться заставить ваш код работать, тем временем вы можете настроить это решение и сохранить предыдущее, если это сработает, а затем преобразовать свое с помощью этого.

Ответ №2:

Вот мой пример кода в VB.Net (вы можете преобразовать его в C #):

 Public Class SignalRHub
    Inherits Hub

    Private Shared hubContext As IHubContext = GlobalHost.ConnectionManager.GetHubContext(Of SignalRHub)()

    Public Sub SendToAll(ByVal msg As String)
        hubContext.Clients.All.addNewMessageToPage(msg)
    End Sub

    Public Shared Sub SendToUser(ByVal user As String, ByVal msg As String)
        hubContext.Clients.Group(user).addNewMessageToPage(msg)
    End Sub

    Public Overrides Function OnConnected() As Task
        Dim name As String = Context.User.Identity.Name
        Groups.Add(Context.ConnectionId, name)
        Return MyBase.OnConnected()
    End Function

End Class
  

Вы должны использовать Group. В принципе, что я делаю, так это то, что 1 группа предназначена для 1 пользователя. Определите по имени пользователя.

Затем просто вызовите функцию:

 Dim user As User = idb.Users.Where(Function(a) a.id = userid).FirstOrDefault
Dim msg as string = "Any notification message"
SignalRHub.SendToUser(user.UserName, msg)
  

Наконец, код javascript для запуска этого:

 var notification = $.connection.signalRHub;
notification.client.addNewMessageToPage = function (msg) {
    $("#notification").prepend(msg);
}
  

Идентификатор уведомления, куда вы хотите поместить уведомление.

Комментарии:

1. Я пытался, но не получаю уведомлений: (можете ли вы помочь мне с кодом c #, который будет работать для входа конкретного пользователя, другой пользователь не должен хотеть видеть уведомления других.