web-dev-qa-db-fra.com

Comment obtenir l'ID de connexion du client signalR côté serveur?

Je dois obtenir l'ID de connexion d'un client. Je sais que vous pouvez l'obtenir du côté client en utilisant $.connection.hub.id. Ce dont j'ai besoin, c'est d'entrer dans un service Web dont je dispose et qui met à jour les enregistrements d'une base de données, puis affiche la mise à jour sur une page Web. Je suis nouveau sur signalR et stackoverflow, alors tout conseil serait apprécié. Sur ma page Web client, j'ai ceci:

<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>

tout fonctionne jusqu'à ce que je veuille mettre à jour la page avec signalR. La fonction de notification de show dans mon hub est la suivante:

//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

comment puis-je envoyer l'ID de connexion à mon service Web?

J'espère que je n'essaye pas de faire quelque chose d'impossible. Merci d'avance.

43
Clint L

La réponse de Taylor fonctionne, cependant, elle ne prend pas en compte une situation dans laquelle un utilisateur a plusieurs onglets de navigateur Web ouverts et donc plusieurs identifiants de connexion différents.

Pour résoudre ce problème, j'ai créé un dictionnaire simultané dans lequel la clé de dictionnaire est un nom d'utilisateur et la valeur de chaque clé est une liste des connexions en cours pour cet utilisateur donné.

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

Sur connecté - Ajout d'une connexion au dictionnaire de cache global:

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();
}

À la déconnexion (fermeture de l'onglet) - Suppression d'une connexion du dictionnaire de cache global:

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

Lorsqu'un client appelle une fonction côté serveur, vous pouvez récupérer son identifiant de connexion via Context.ConnectionId. Maintenant, si vous souhaitez accéder à cet identifiant de connexion via un mécanisme situé en dehors d'un hub, vous pouvez:

  1. Il suffit que le Hub appelle votre méthode externe en lui transmettant l’ID de connexion.
  2. Gérer une liste de clients connectés aka public static ConcurrentDictionary<string, MyUserType>... en ajoutant au dictionnaire dans OnConnected et en en supprimant dans OnDisconnected. Une fois que vous avez votre liste d'utilisateurs, vous pouvez l'interroger via votre mécanisme externe.

Ex 1:

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

Ex 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

J'espère que cela t'aides!

70
N. Taylor Mullen

Je prie de différer sur la reconnexion. Le client reste dans la liste mais le connectid va changer. Je fais une mise à jour de la liste statique lors de la reconnexion pour résoudre ce problème.

5
Jeff