在SignalR中通过UserId查找连接

时间:2012-11-10 17:42:30

标签: c# asp.net signalr

我有一个网页,它使用ajax轮询从服务器获取股市更新。我想改用SignalR,但我很难理解它是如何工作的。

好吧,这不是真正的股票市场更新,但这个比喻有效。

我见过的SignalR示例将消息发送到当前连接,所有连接或组。在我的例子中,股票更新发生在当前连接之外,所以没有“当前连接”这样的东西。并且用户的帐户与少数股票相关联,因此向所有连接或组发送股票通知也不起作用。 我需要能够找到与某个userId相关联的连接。

这是一个假代码示例:

foreach(var stock in StockService.GetStocksWithBigNews())
{
    var userIds = UserService.GetUserIdsThatCareAboutStock(stock);

    var connections = /* find connections associated with user ids */;

    foreach(var connection in connections)
    {
        connection.Send(...);
    }
}

In this question on filtering connections,他们提到我可以将当​​前连接保留在内存中,但(1)它不适合扩展,(2)它对多节点网站不利。这两点对我们目前的应用至关重要。这让我觉得我必须向所有节点发送消息以找到连接到每个节点的用户>>我的大脑在混乱中爆炸。

问题

如何为可扩展的特定用户找到连接?我是否以错误的方式思考这个问题?

2 个答案:

答案 0 :(得分:6)

昨晚我创建了一个小项目来学习这个。我使用了1.0 alpha,直接向前。我创建了一个Hub,并从那里开始工作:)

我的项目我有N个计算单位(一些服务器处理工作),当他们启动时会调用ComputeUnitRegister。

await HubProxy.Invoke("ComputeUnitReqisted", _ComputeGuid);

每次他们做某事他们都会打电话

HubProxy.Invoke("Running", _ComputeGuid);

HubProxy是:

HubConnection Hub = new HubConnection(RoleEnvironment.IsAvailable ?
                    RoleEnvironment.GetConfigurationSettingValue("SignalREndPoint"):
                    "http://taskqueue.cloudapp.net/");
IHubProxy HubProxy = Hub.CreateHubProxy("ComputeUnits"); 

我使用了RoleEnviroment.IsAvailable,因为我现在可以将其作为Azure角色,控制台应用程序或.NET 4.5中的任何内容运行。 Hub被放置在一个MVC4网站项目中,就像这样开始:

        GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(50);
        RouteTable.Routes.MapHubs();

public class ComputeUnits : Hub
{
     public Task Running(Guid MyGuid)
     {
         return Clients.Group(MyGuid.ToString()).ComputeUnitHeartBeat(MyGuid,
                DateTime.UtcNow.ToEpochMilliseconds());            
     }
     public Task ComputeUnitReqister(Guid MyGuid)
     {
         Groups.Add(Context.ConnectionId, "ComputeUnits").Wait(); 
         return Clients.Others.ComputeUnitCameOnline(new { Guid = MyGuid,
                HeartBeat = DateTime.UtcNow.ToEpochMilliseconds() });           
     }
     public void SubscribeToHeartBeats(Guid MyGuid)
     {
         Groups.Add(Context.ConnectionId, MyGuid.ToString());
     }
}

我的客户端是Javascript客户端,有方法(如果您需要查看此代码,请告诉我)。但基本上它们会列出ComputeUnitCameOnline的列表,当它运行时,它们会调用服务器SubscribeToHeartBeats。这意味着每当服务器计算单元正在做一些工作时,它将调用Running,这将在javascript客户端上触发ComputeUnitHeartBeat

我希望您可以使用它来查看如何使用组和连接。最后,它还通过添加几行代码来扩展多个azure角色:

    GlobalHost.HubPipeline.EnableAutoRejoiningGroups();
    GlobalHost.DependencyResolver.UseServiceBus(
        serviceBusConnectionString,
        2,
        3,
        GetRoleInstanceNumber(),
          topicPathPrefix /* the prefix applied to the name of each topic used */
        );

您可以在Azure上的servicebus上获取连接字符串,记住Provider = SharedSecret。但是当添加nuget打包时,connectionstring语法也会粘贴到web.config中。 2是分开多少主题。主题可以包含1Gb的数据,因此根据性能您可以增加它。 3是将其拆分的节点数。我使用3是因为我有2个Azure实例和我的本地主机。您可以像这样获取RoleNumber(请注意,我将本地主机硬编码为2)。

private static int GetRoleInstanceNumber()
{
    if (!RoleEnvironment.IsAvailable)
        return 2;

    var roleInstanceId = RoleEnvironment.CurrentRoleInstance.Id;
    var li1 = roleInstanceId.LastIndexOf(".");
    var li2 = roleInstanceId.LastIndexOf("_");
    var roleInstanceNo = roleInstanceId.Substring(Math.Max(li1, li2) + 1);
    return Int32.Parse(roleInstanceNo);
}

您可以看到它们全部位于:http://taskqueue.cloudapp.net/#/compute-units

答案 1 :(得分:2)

使用SignalR时,在客户端连接到服务器后,它们会被提供一个连接ID(这对于提供实时通信至关重要)。是的,它存储在内存中,但SignalR也可以用在多节点环境中。例如,您可以使用Redis甚至是Sql Server背板(更多内容)。总而言之,我们通过背板/服务总线为您提供横向扩展方案,而无需担心。