SignalR LongPolling多个Groups.Add为单个客户端Exception

时间:2014-06-12 19:10:37

标签: c# javascript signalr

我一直在努力解决这个问题。我们正在使用最新的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);
        }
    }
}

控制器采用整数作为输入,这是要执行的添加操作的数量。例如,如果您致电:

http://yourip.com/WebApplicationName/SignalRTest/Index/1一个Groups.Add 正常运行 http://yourip.com/WebApplicationName/SignalRTest/Index/2两个Groups.Add 正常运行 http://yourip.com/WebApplicationName/SignalRTest/Index/3三个Groups.Add 正常运行 http://yourip.com/WebApplicationName/SignalRTest/Index/4四个Groups.Add 正常运行 http://yourip.com/WebApplicationName/SignalRTest/Index/5五个Groups.Add 正常运行 http://yourip.com/WebApplicationName/SignalRTest/Index/6六个Groups.Add 已损坏 http://yourip.com/WebApplicationName/SignalRTest/Index/7七个Groups.Add 已损坏 http://yourip.com/WebApplicationName/SignalRTest/Index/8八个Groups.Add 已损坏 http://yourip.com/WebApplicationName/SignalRTest/Index/9九个Groups.Add 已损坏 http://yourip.com/WebApplicationName/SignalRTest/Index/10十个Groups.Add 已损坏

...

当我说破了,我得到了一个&#34; System.Threading.Tasks.TaskCanceledException&#34;在TestHub.cs上等待任务完成的行。 ServerSentEvents一切正常,但对于LongPolling,问题依然存在。我究竟做错了什么?使用LongPolling,我不能拥有超过5个SignalR组吗?帮我! :)


更新:在客户端调用之间使用setTimeout进行1毫秒的休眠可以解决问题。这似乎减轻了网络选项卡中待处理连接的数量。当达到单个浏览器连接限制时,可能会出现添加到组的能力。很高兴知道为什么这不起作用。

2 个答案:

答案 0 :(得分:2)

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

Groups.Add返回的任务仅在从消息总线收到ACK消息时才完成,该消息指示已发送客户端的消息(通知组添加)。 如果有超过5个(或浏览器强制执行的任何数字)挂起与客户端的addToGroupAndBroadcast调用绑定的AJAX请求,则无法发送到客户端的消息。如果您将完成回调附加到客户来电:

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

你会看到第一个电话几乎立即完成。

这是第一次Groups.Add调用返回的时间。向sayHello发送的消息不再发送,因为它需要另一个打开的轮询请求,客户端正在创建该请求,但由于客户端有多个其他未决请求已经排队,因此无法处理(这些都在等待addToGroupAndBroadcast完成)。

因此,在第一次调用Groups.Add之后,服务器无法向客户端发送任何内容,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);
    }
}

答案 1 :(得分:0)

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

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

  

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

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