web-dev-qa-db-fra.com

Mappage des connexions de SignalR aux utilisateurs

Prenons l'exemple d'une application Web telle que Facebook, capable d'envoyer des notifications en temps réel aux utilisateurs.

Quel est le meilleur moyen, en utilisant asp.net SignalR , de garder trace des identifiants de connexion appartenant à quel utilisateur, même s’il se déconnecte ou se reconnecte ultérieurement?

25
Daniel Hursan

Découvrez le blog suivant:

Mappage des connexions ASP.NET SignalR aux utilisateurs d'applications réelles

En bref, vous ajouteriez les identifiants de connexion à l’utilisateur sur la méthode OnConnected et supprimeriez cette connexion à la méthode OnDisconnected. Gardez à l'esprit qu'un utilisateur d'application peut avoir plusieurs connexions. Vous devez donc avoir une relation un à plusieurs entre votre utilisateur et les identifiants de connexion. Le post ci-dessus est expliqué en détail avec un échantillon.

26
tugberk

Je l'ai fait pour une application interne. La façon dont je l'ai fait est que lorsqu'un utilisateur se connecte, le serveur demande à l'utilisateur de s'enregistrer. De cette façon, je sais que non seulement un utilisateur est connecté et son identifiant ID de connexion, mais il peut également me dire toute autre information (comme un nom d'utilisateur ou autre). 

Quand ils se reconnectent, je leur demande de le refaire. 

SignalR conservera le même ID de connexion par client même s’ils se reconnectent, ce qui est Nice. Une reconnexion n'est pas la même chose qu'une connexion initiale. Les nouvelles connexions indiquent un nouveau client, mais une reconnexion a lieu sur le même client. 

Dans mon application, je conservais un dictionnaire threadsafe distinct, que je gardais en mémoire quel utilisateur et quel ID de connexion faisait quoi. De cette façon, je peux dire "oh, envoyer un message à l'utilisateur ABC" et rechercher son ID de connexion. Agissez ensuite sur l'objet clients du concentrateur dans signalR pour cet ID connexion. Si vous le faites de cette façon, vous pouvez même avoir le même "utilisateur" dans plusieurs connexions. Imaginez que l'utilisateur "abc" soit ouvert dans deux onglets du navigateur. Si vous utilisiez strictement connectionID, ils seraient techniquement deux utilisateurs différents. Cependant, en maintenant une sorte de collection locale regroupant des utilisateurs et des connexions, vous pouvez désormais avoir plusieurs connexions pour le même utilisateur. 

Je devrais mentionner que si vous le faites de cette façon, vous devez vous assurer que votre site gère ce qui se passe quand il redémarre et perd toutes les informations de connexion. Pour moi, lorsque quelqu'un se reconnecte, je lui demande de se ré-identifier. De cette façon, je peux reconstruire mon dictionnaire local lorsque le serveur est mis en ligne sans souci. Il y a plus de frais généraux car vous demandez maintenant à tous vos clients de vous envoyer des informations, mais selon votre cas d'utilisateur, cela peut être échelonné, groupé ou autrement distribué pour vous aider à gérer la charge.

En règle générale, lorsque vous obtenez des informations locales (que vous demandiez à l'utilisateur de les fournir) ou des informations de session en contexte http, vous devez les suivre vous-même.

6
devshorts

Eh bien, j’ai utilisé une approche différente, j’ai étendu la classe ApplicationUser comme suit:

    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.Microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
    //public int ApplicationUserId { get; set; }
    //public string Name { get; set; }
    //public string Address { get; set; }
    //public string City { get; set; }
    //public string State { get; set; }
    //public string Zip { get; set; }
    [Required]
    public string Email { get; set; }
    [Required]
    public override string UserName { get; set; }
    [NotMapped]
    public string ConnectionId { get; set; }
    [NotMapped]
    public string ChattingUserConnectionId { get; set; }
    //public string HomeTown { get; set; }
    //public DateTime? BirthDate { get; set; }
}

Et dans mon hub, je fais quelque chose comme ça:

public class ChatHub : Hub
{
    #region Data Members
    private static ApplicationDbContext applicationDbContext = new ApplicationDbContext();
    private static UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
    private static List<ApplicationUser> connectedUsers = new List<ApplicationUser>();

Et lorsqu'un utilisateur se connecte au chat, je récupère son objet ApplicationUser par son nom d'utilisateur et l'ajoute à la liste des utilisateurs connectés. Quand il se déconnecte, je le retire.

J'ai rencontré des exceptions aléatoires avec des états EF et autres, qui m'ont obligé à créer ApplicationDbContext et UserManager à chaque accès au lieu de le définir dans un objet statique:

 private ApplicationUser GetCurrentUser()
    {
        ApplicationDbContext applicationDbContext = new ApplicationDbContext();
        UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(applicationDbContext));
        var userName = Context.User.Identity.GetUserName();
        var user = userManager.FindByName<ApplicationUser>(userName);

        return user;
    }

Modifier:

Le code du hub rencontre des problèmes pour charger les objets enfants de l'utilisateur. Ce code, également utilisé dans le modèle asp.net, fonctionnera mieux. ApplicationDBContext n’est pas nécessaire:

    private ApplicationUserManager _userManager
    {
        get
        {
            return HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
    }


    var user = _userManager.FindByName<ApplicationUser, string>(userName);
3
Ronen Festinger

Il existe un très bon article dans la section de didacticiel SignalR d’ASP.NET. J'ai inclus le paragraphe d'introduction ci-dessous.

Mappage des utilisateurs de SignalR sur des connexions

Chaque client qui se connecte à un concentrateur transmet un identifiant de connexion unique. Vous pouvez récupérez cette valeur dans la propriété Context.ConnectionId du hub le contexte. Si votre application doit mapper un utilisateur sur l'ID de connexion et persistez ce mappage, vous pouvez utiliser l’un des éléments suivants:

  • Le fournisseur d'identifiant utilisateur (SignalR 2)
  • Stockage en mémoire, tel qu'un dictionnaire
  • Groupe SignalR pour chaque utilisateur

Stockage externe permanent, tel qu'une table de base de données ou une table Azure stockage Chacune de ces implémentations est présentée dans cette rubrique. Tu utilises les méthodes OnConnected, OnDisconnected et OnReconnected du hub classe pour suivre le statut de connexion de l'utilisateur.


Fournisseur d'identifiant utilisateur

Si vous utilisez le fournisseur d'appartenance standard d'ASP.NET (IPrincipal.Identity.Name), vous pouvez simplement procéder comme suit pour accéder à un client basé sur un compte d'utilisateur. Si vous avez votre propre système utilisateur, vous pouvez créer votre propre fournisseur.

public class MyHub : Hub
{
    public void Send(string userId, string message)
    {
        Clients.User(userId).send(message);
    }
}
0
Simon_Weaver