C# SignalR 异常 - 在收到调用结果之前连接开始重新连接

Posted

技术标签:

【中文标题】C# SignalR 异常 - 在收到调用结果之前连接开始重新连接【英文标题】:C# SignalR Exception - Connection started reconnecting before invocation result was received 【发布时间】:2015-08-31 16:19:49 【问题描述】:

我正在开发 2 个应用程序,第一个是 C# 控制台应用程序,另一个是 Asp.net Web 应用程序。我正在使用 SignalR 将两者连接起来。

这是我的 C# 控制台应用程序(客户端)

public class RoboHub

    public static IHubProxy _hub;

    public RoboHub()
    
        StartHubConnection();
        _hub.On("GetGoals", () => GetGoals());
        _hub.On("PrintMessageRobot", x => PrintMessageRobot(x));

        Thread thread = new Thread(MonitorHubStatus);
        thread.Start();
    

    public void GetGoals()
    
        //TODO: Does stuff
    

    public void PrintMessageRobot(string msg)
    
        Console.WriteLine(msg);
    

    public void StartHubConnection()
    
        Console.WriteLine("Robo Hub Starting");
        string url = @"http://localhost:46124/";
        var connection = new HubConnection(url);
        _hub = connection.CreateHubProxy("WebHub");
        connection.Start().Wait();
        Console.WriteLine("Robo Hub Running");
    

    public void MonitorHubStatus()
    
        while (true)
        
            Thread.Sleep(1000);
            _hub.Invoke("Ping", "ping").Wait();
            Console.WriteLine("WebHub Pinged : " + DateTime.Now);
        
    

当控制台应用程序运行时,它会创建一个 RoboHub 类的实例。这反过来启动到 SignalR 集线器的连接,并在单独的线程上启动方法 MonitorHubStatus,这是我实现的,用于检查 C# 控制台应用程序客户端是否仍主动连接到集线器。

这是我的 Web 中心(在 Asp.net Web 应用程序中)

public class WebHub : Hub

    /// <summary>
    /// This method should be called by the Web Clients. 
    /// This method should call the method on the robot clients.
    /// </summary>
    public void GetGoalsHub()
    
        lock (UserHandler.Connections)
        
            if (UserHandler.Connections.Any(connection => connection.Contains("Robot")))
            
                Clients.All.GetGoals();
            
        
        //TODO add Error method to call on the client
    

    /// <summary>
    /// Override Methods
    /// </summary>
    /// <returns></returns>
    public override Task OnConnected()
    
        lock (UserHandler.Connections)
        
            //Find out who is connecting based on the User-Agent header
            var query = (from r in Context.Headers
                where r.Key == "User-Agent"
                select r).SingleOrDefault().ToString();

            if (query.Contains("SignalR.Client.NET45"))
            
                UserHandler.Connections.Add("Robot : " + Context.ConnectionId);
            
            else
            
                UserHandler.Connections.Add("Web Application : " + Context.ConnectionId);
                GetGoalsHub();
            
        
        Clients.All.UpdateConnections(UserHandler.Connections);
        return base.OnConnected();
    

    public override Task OnDisconnected(bool stopCalled)
    
        lock (UserHandler.Connections)
        
            for (int i = 0; i < UserHandler.Connections.Count; i++)
            
                if (UserHandler.Connections[i].Contains(Context.ConnectionId))
                
                    UserHandler.Connections.Remove(UserHandler.Connections[i]);
                
            
        
        Clients.All.UpdateConnections(UserHandler.Connections);
        return base.OnDisconnected(stopCalled);
    

    public void Ping(string msg)
    
        Clients.All.PrintMessageRobot("Pong : " + DateTime.Now);
    

public static class UserHandler

    public static List<string> Connections = new List<string>(); 

目前这两个应用程序似乎工作了一段时间,直到一段时间后这个错误随机出现:

在收到调用结果之前连接开始重新连接。

Web 中心还应该调用 C# 控制台客户端上的任何其他方法,例如 GetGoals 方法。 'Ping Pong' 方法冻结,并在一段时间后引发类似的异常。在整个过程中,Web 客户端继续完美运行,并且 Web 客户端可以与中心服务器来回通信。

谁能提出问题可能是什么? 编辑:进一步的调查使我相信这与线程有关,但是很难找到问题的根源。

【问题讨论】:

这可能是因为邮件大小,就像 Damian 解释的 [here]。 [这里]:github.com/SignalR/SignalR/issues/2631#issuecomment-47011184 【参考方案1】:

问题在于调用调用:

_hub.Invoke("MethodName", "Parameters").Wait();

在这里我告诉它等待响应,但是我没有在 Web 服务器中编写任何响应机制。

这个错误是通过切换到修复:

_hub.Invoke("MethodName", "Parameters");

现在它遵循“即发即弃”的方法,现在不再出现错误。如果其他人收到此错误,请务必检查您是否需要回复。

【讨论】:

感谢您花时间发布您的解决方案。我遇到了类似的事情,这很有帮助。 这不是正确的答案。在这里,Wait() 让你的代码等待异步调用的执行(这是 Invoke,可能会导致死锁),并且你不需要在你的 web 服务器中编写任何回复机制,服务器将返回一个无论您的集线器代码做什么,都会响应。通过删除Wait(),您只是在使用fire and forget 模式,通过启动异步调用而不等到它完成。这样做只是一个糟糕的解决方法,可能会出现其他问题,您应该更好地了解信号生命周期并了解您的代码为何会损坏。【参考方案2】:

如果发送到服务器端的数据是“不可序列化”(例如)不具有 [Serializable] 属性的业务对象列表,您将收到相同的错误消息

【讨论】:

【参考方案3】:

当负载过大时,我也遇到了同样的异常。我通过在 signlr.net 的启动声明中更改以下行来修复它。它消除了大小限制

GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null;

【讨论】:

以上是关于C# SignalR 异常 - 在收到调用结果之前连接开始重新连接的主要内容,如果未能解决你的问题,请参考以下文章

SignalR 2.2 客户端未收到任何消息

从 C# 调用 C++ DLib 导致错误分配异常

如何在 SignalR 客户端中使用 async/await 和 hub.On

自定义 SignalR 的错误消息

从不同的 AppDomain 调用 SignalR 方法

从 signalR 更新后如何重新加载我的表