web-dev-qa-db-ja.com

サーバー側でsignalRクライアントの接続IDを取得する方法は?

クライアントの接続IDを取得する必要があります。 $.connection.hub.idを使用してクライアント側から取得できることを知っています。私が必要なのは、データベースのレコードを更新するWebサービスを使用しているときにアクセスし、Webページに更新を表示することです。 signalRとstackoverflowは初めてなので、アドバイスをいただければ幸いです。私のクライアントのウェブページには次のものがあります:

<script type="text/javascript">
    $(function () {
        // Declare a proxy to reference the hub. 
        var notify = $.connection.notificationHub;

        // Create a function that the hub can call to broadcast messages.
        notify.client.broadcastMessage = function (message) {
            var encodedMsg = $('<div />').text(message).html();// Html encode display message.
            $('#notificationMessageDisplay').append(encodedMsg);// Add the message to the page.
        };//end broadcastMessage

        // Start the connection.
        $.connection.hub.start().done(function () {
            $('#btnUpdate').click(function () {
                //call showNotification method on hub
                notify.server.showNotification($.connection.hub.id, "TEST status");
            });
        });


    });//End Main function


</script>

signalRを使用してページを更新するまで、すべてが機能します。私のハブのショー通知機能はこれです:

//hub function
public void showNotification(string connectionId, string newStatus){               
    IHubContext context = GlobalHost.ConnectionManager.GetHubContext<notificationHub>();
    string connection = "Your connection ID is : " + connectionId;//display for testing
    string statusUpdate = "The current status of your request is: " + newStatus;//to be displayed
    //for testing, you can display the connectionId in the broadcast message
    context.Clients.Client(connectionId).broadcastMessage(connection + " " + statusUpdate);
}//end show notification

connectionidをWebサービスに送信するにはどうすればよいですか?

できれば、不可能なことをしようとしていないことを願っています。前もって感謝します。

43
Clint L

Taylorの答えは機能しますが、ユーザーが複数のWebブラウザーのタブを開いているため、複数の異なる接続IDを持っている状況は考慮されていません。

これを修正するために、辞書キーがユーザー名で、各キーの値がそのユーザーの現在の接続のリストである並行辞書を作成しました。

public static ConcurrentDictionary<string, List<string>> MyUsers = new ConcurrentDictionary<string, List<string>>();

接続時-グローバルキャッシュディクショナリへの接続の追加:

public override Task OnConnected()
{
    Trace.TraceInformation("MapHub started. ID: {0}", Context.ConnectionId);

    var userName = "testUserName1"; // or get it from Context.User.Identity.Name;

    // Try to get a List of existing user connections from the cache
    List<string> existingUserConnectionIds;
    ConnectedUsers.TryGetValue(userName, out existingUserConnectionIds);

    // happens on the very first connection from the user
    if(existingUserConnectionIds == null)
    {
        existingUserConnectionIds = new List<string>();
    }

    // First add to a List of existing user connections (i.e. multiple web browser tabs)
    existingUserConnectionIds.Add(Context.ConnectionId);


    // Add to the global dictionary of connected users
    ConnectedUsers.TryAdd(userName, existingUserConnectionIds);

    return base.OnConnected();
}

切断時(タブを閉じる)-接続をグローバルキャッシュディクショナリから削除します。

public override Task OnDisconnected(bool stopCalled)
{
    var userName = Context.User.Identity.Name;

    List<string> existingUserConnectionIds;
    ConnectedUsers.TryGetValue(userName, out existingUserConnectionIds);

    // remove the connection id from the List 
    existingUserConnectionIds.Remove(Context.ConnectionId);

    // If there are no connection ids in the List, delete the user from the global cache (ConnectedUsers).
    if(existingUserConnectionIds.Count == 0)
    {
        // if there are no connections for the user,
        // just delete the userName key from the ConnectedUsers concurent dictionary
        List<string> garbage; // to be collected by the Garbage Collector
        ConnectedUsers.TryRemove(userName, out garbage);
    }

    return base.OnDisconnected(stopCalled);
}
2
Matthew C

クライアントがサーバー側で関数を呼び出すと、Context.ConnectionIdを介して接続IDを取得できます。ハブの外部のメカニズムを介してその接続IDにアクセスしたい場合、次のことができます。

  1. ハブに、接続IDを渡して外部メソッドを呼び出させるだけです。
  2. OnConnectedの辞書に追加し、OnDisconnectedの辞書から削除することで、public static ConcurrentDictionary<string, MyUserType>...などの接続されたクライアントのリストを管理します。ユーザーのリストを取得したら、外部メカニズムを使用してクエリを実行できます。

例1:

public class MyHub : Hub
{
    public void AHubMethod(string message)
    {
        MyExternalSingleton.InvokeAMethod(Context.ConnectionId); // Send the current clients connection id to your external service
    }
}

例2:

public class MyHub : Hub
{
    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 void PushData(){
        //Values is copy-on-read but Clients.Clients expects IList, hence ToList()
        Clients.Clients(MyUsers.Keys.ToList()).ClientBoundEvent(data);
    }
}

public class MyUserType
{
    public string ConnectionId { get; set; }
    // Can have whatever you want here
}

// Your external procedure then has access to all users via MyHub.MyUsers

お役に立てれば!

70

再接続をお願いします。クライアントはリストに残りますが、connectidは変更されます。これを解決するために、再接続時に静的リストを更新します。

5
Jeff