Je viens de découvrir que vous ne pouvez pas accéder à la session en cours dans SignalR Hub.
Mon scénario est simplifié: j'ai essayé d'écrire un chat.
Le nom de l'utilisateur actuel a été conservé dans la session.
J'ai utilisé SignalR pour mettre à jour (un groupe de connexions) chaque nouveau message.
Maintenant, je vois que je ne peux pas accéder au nom de l'utilisateur actuel via le hub.
Je suppose qu'il pourrait y avoir des solutions de contournement, mais est-ce que cette implémentation a été mal conçue?
Devrais-je ne pas utiliser SignalR à cette fin? Ou ne devrais-je pas utiliser Session
de cette manière?
Vous ne devriez pas utiliser Session avec SignalR (voir SignalR n'utilise pas Session sur le serveur ). Vous identifiez les connexions logiques par leur ID de connexion que vous pouvez mapper sur des noms d'utilisateur .
Le problème sous-jacent est que l'accès à SessionState est sérialisé dans ASP.NET pour garantir la cohérence de l'état, de sorte que chaque demande adressée au concentrateur bloque les autres demandes. Dans le passé, un accès limité en lecture seule (je suppose (mais je ne peux pas confirmer car le Gist est parti) en définissant EnableSessionstate sur read-only , ce qui évite le problème de verrouillage que j'ai décrit) était possible, mais le support pour ceci a été abandonné . Voir également divers autres lieux où l’équipe de SignalR a fait des déclarations similaires. Enfin, il existe une déclaration dans le document officiel documentation à propos du HTTPContext.Current.Session
.
Vous pouvez envoyer des valeurs du client au concentrateur de serveur via Query String.
Avant la méthode $.connection.hub.start()
, vous pouvez ajouter quelque chose comme ceci:
Code client JS:
// Replace "some value" with the session value or anything you want
$.connection.hub.qs = { "Name": "some value" };
$.connection.hub.start()...bla bla bla
Du côté du serveur sur le hub, vous pouvez utiliser cette méthode avec n’importe quelle méthode:
string ClientValue= Context.QueryString["Name"].ToString();
Je n'ai pas testé avec des sessions, mais bien sûr, côté client, vous pourriez être aussi génial que possible.
J'étais dans une situation où je ne pouvais pas utiliser l'utilisateur/identité parce que la session n'avait pas encore été authentifiée, j'ai donc utilisé la valeur réelle du cookie de session.
[HubName("headerHub")]
public class HeaderHub : Hub
{
static HeaderHub()
{
EventManager.CartUpdated += Update;
EventManager.LoggedOut += Update;
EventManager.LoggedIn += Update;
}
public override Task OnConnected()
{
var group = Context.Request.Cookies["ASP.NET_SessionId"].Value;
Groups.Add(Context.ConnectionId, group);
return base.OnConnected();
}
private static void Update(object sender, SessionEventArgs e)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<HeaderHub>();
hubContext.Clients.Group(e.SessionId).onUpdateHeader();
}
}
Je suis sûr que quelqu'un trouvera quelque chose qui ne va pas avec cette solution et si c'est le cas, n'hésitez pas à faire un commentaire car je voudrais une meilleure façon de lier une session à un ensemble de clients à informer.
La meilleure approche consiste à utiliser un cookie au lieu d'une session. car comme mentionné ci-dessus, vous ne pouvez pas utiliser la session. Ainsi, lorsque l'utilisateur se connecte à votre système, mettez son identifiant unique (tel que nom d'utilisateur) dans un cookie. puis travaillez avec le cookie où vous voulez que la session d'accès. comme ci-dessous ...
public class CustomUserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
return request.Cookies["ODPUserID"].Value;
}
}