SignalR长轮询多个组.为单个客户端添加Exception

本文关键字:单个 客户端 添加 Exception SignalR | 更新日期: 2023-09-27 18:08:27

我已经纠结了一段时间了。我们使用的是最新的SignalR 2.0.3。当我们添加到多个SignalR组时,问题就发生了。只有当对同一个connectionId使用不同的组名进行多个添加时,才会抛出异常。只有在选择LongPolling传输时才会引发异常。该异常只会在添加6+唯一组名,5或更少时抛出,并且正常工作。

下面是一个简化的例子:

Index.cshtml:

    @model Int32?
    <!DOCTYPE html>
    <head>
        <title></title>
<script src="@Url.Content("~/Scripts/jquery.min.js")" type="text/javascript"/>
<script src="@Url.Content("~/Scripts/jquery.signalR-2.0.3.min.js")"
    type="text/javascript" />
<script src="@Url.Content("~/signalr/hubs")" type="text/javascript"/>
    </head>
    <script>
        _testHub = $.connection.testHub;
        _testHub.client.sayHello = sayHello;
        $.connection.hub.start({ transport: 'longPolling' })
            .done(function() {
                addAllGroups();
            });
        function sayHello(aMessage, aGroupName) {
            console.info("GroupName: " + aGroupName 
    + " Message Sent:" + aMessage);
        };
        function addAllGroups() {
            for (var i = 0; 
              i < @(Model.HasValue ? Model.Value : 1 ); i++) {
                  addToGroupAndBroadcast(i);
            }
        };
        function addToGroupAndBroadcast(aGroupName) {
            _testHub.server.addToGroupAndBroadcast(aGroupName)
                .fail(function (desc) {
                    console.info("Error: " + desc);
                });
        };
    </script>

SignalRTestController.cs:

using System;
using System.Web.Mvc;

namespace Instrumar.ProductionDashboard.Controllers
{
    public class SignalRTestController : Controller
    {
        #region Public Members
        public ActionResult Index()
        {
            return View((int?)Convert.ToInt32(Request.Url.Segments[4]));
        }
        #endregion
    }
}

TestHub.cs:

using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;

namespace Instrumar.ProductionDashboard.Hubs
{
    public class TestHub : Hub
    {
        #region Public Members
        public void AddToGroupAndBroadcast(string aGroupName)
        {
            GlobalHost.ConnectionManager.GetHubContext<TestHub>().Groups.Add(Context.ConnectionId, aGroupName).Wait();
            Clients.Group(aGroupName).sayHello("Hello", aGroupName);
        }
        #endregion
    }
}

Startup.cs:

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var lHubConfiguration = new HubConfiguration {EnableDetailedErrors = true};
            app.UseErrorPage();
            app.MapSignalR(lHubConfiguration);
        }
    }
}

控制器接受一个整数作为输入,该整数表示要执行的Add操作的数量。例如,如果调用:

http://yourip.com/WebApplicationName/SignalRTest/Index/1 one Groups。添加可以正常工作http://yourip.com/WebApplicationName/SignalRTest/Index/2两组。添加可以正常工作http://yourip.com/WebApplicationName/SignalRTest/Index/3三组。添加可以正常工作http://yourip.com/WebApplicationName/SignalRTest/Index/4四组。添加可以正常工作http://yourip.com/WebApplicationName/SignalRTest/Index/5五组。添加可以正常工作http://yourip.com/WebApplicationName/SignalRTest/Index/6六组。添加http://yourip.com/WebApplicationName/SignalRTest/Index/7七组。添加http://yourip.com/WebApplicationName/SignalRTest/Index/8八组。添加http://yourip.com/WebApplicationName/SignalRTest/Index/9九组。添加http://yourip.com/WebApplicationName/SignalRTest/Index/10十组。添加

当我说"坏了"时,我得到的是"System.Threading.Tasks"。TaskCanceledException"在testthub .cs中在线等待任务完成。对于ServerSentEvents,一切工作正常,但对于LongPolling,问题存在。我做错了什么?我可以不拥有超过5个长轮询SignalR组吗?帮帮我!:)


更新:在客户端调用之间使用setTimeout设置1毫秒的睡眠修复了这个问题。这似乎减轻了网络选项卡中挂起连接的数量。当您达到单个浏览器连接限制时,添加到组的能力可能会发生一些问题。如果能确切地知道为什么这不起作用,那就太好了。

SignalR长轮询多个组.为单个客户端添加Exception

你可以有5个以上的长轮询组,但是你必须通过在循环中不添加组来解决连接问题。

Groups.Add返回的任务只有在从消息总线接收到ACK消息时才完成,该ACK消息表明客户端(通知其组添加)的消息已经发送。如果有超过5个(或浏览器强制的任何数字)与客户端的addToGroupAndBroadcast调用相关联的待处理AJAX请求,则无法将消息发送到客户端。如果你在客户端调用中附加了一个done回调:

_testHub.server.addToGroupAndBroadcast(groupName).done(function() {
    console.log("complete");
});

您将看到第一个调用几乎立即完成。

这是当第一个组。添加调用返回。给sayHello的消息不再发送,因为它需要另一个打开的轮询请求,该请求是客户端正在创建的,但不会得到处理,因为有多个来自客户端的其他未决请求已经先排队(并且这些请求都在等待addToGroupAndBroadcast完成)。

在第一次呼叫Groups之后。另外,服务器无法向客户端发送任何东西,MessageHub无法发送ACK,这将解决剩余的Groups.Add承诺。结果,由于超时,这些任务的TaskCanceledException被抛出。

作为一种解决方法,我建议创建一个hub方法,它接受组名数组:

public async Task AddToGroups(string[] names)
{
    foreach (var name in names)
    {
        await Groups.Add(Context.ConnectionId, name);
        Clients.Group(name).sayHello("Hello", name);
    }
}

看起来这里有一个相关的问题已经修复https://github.com/SignalR/SignalR/issues/1155。如果是这样,您将不得不提取代码并重新编译自己的DLL。此外,您的错误也可能是由超时引起的。

这也可能与你的问题有关:

…因为您正在尝试的连接idRemove可能不再可用。在这种情况下,在请求超时后抛出TaskCanceledException。

Ref。http://www.asp.net/signalr/overview/signalr-20/hubs-api/working-with-groups