【问题标题】:SignalR client is reconnected after Owin restart, but message is not published重启 Owin 后 SignalR 客户端重新连接,但未发布消息
【发布时间】:2014-05-20 12:26:19
【问题描述】:

设置:

  1. SignalRServer 控制台应用程序:Microsoft.AspNet.SignalR.SelfHost v2.0.3
  2. SignalRClient 控制台应用程序:Microsoft.AspNet.SignalR.Client v2.0.3
  3. .NET 4.5.1

我执行以下操作:

  1. 在客户端按回车键,服务器和客户端再次收到一条消息
  2. 通过点击服务器控制台中的任意键来处理服务器
  3. 在服务器控制台中按任意键重新启动服务器
  4. 客户端重新连接
  5. 在客户端按回车键,服务器收到消息,但再也没有到达客户端

我希望客户端再次收到该消息。我怀疑这与自托管有关,因为我尝试在运行 IIS 的 Web 应用程序中针对同一个集线器运行客户端并成功。

有什么想法吗?

更新:如果服务器控制台进程被杀死并重新启动,它能够重新连接并再次检索消息。

服务器代码

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

namespace SignalRServer
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            const string url = "http://localhost:8081";

            while (true)
            {
                using (WebApp.Start<Startup>(url))
                {
                    Console.WriteLine("Server running on {0}. Hit any key to stop.", url);
                    Console.ReadLine();
                }

                Console.WriteLine("Server stopped");

                Console.WriteLine("Hit any key to restart, Esc to exit");

                ConsoleKeyInfo ki = Console.ReadKey(true);

                if (ki.Key == ConsoleKey.Escape)
                    return;
            }
        }
    }

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }

    public class AuthenticationHub : Hub
    {
        public void BroadcastMessageToAll(string message)
        {
            Clients.All.sendMessageToClient(message);
            Console.WriteLine("sendMessageToClient: " + message);
        }

        public override Task OnConnected()
        {
            Console.WriteLine("OnConnected " + Context.ConnectionId);
            return base.OnConnected();
        }

        public override Task OnReconnected()
        {
            Console.WriteLine("OnReconnected " + Context.ConnectionId);
            return base.OnReconnected();
        }

        public override Task OnDisconnected()
        {
            Console.WriteLine("OnDisconnected " + Context.ConnectionId);
            return base.OnReconnected();
        }
    }
}

客户端代码

using System;
using Microsoft.AspNet.SignalR.Client;

namespace SignalRClient
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                var hubConnection = new HubConnection("http://localhost:8081/signalr/hubs");

                hubConnection.Closed += () => Console.WriteLine("Closed");
                hubConnection.StateChanged += e => Console.WriteLine("StateChanged: " + e.OldState + " " + e.NewState);
                var hubProxy = hubConnection.CreateHubProxy("AuthenticationHub");

                hubProxy.On<string>("sendMessageToClient",
                    info => Console.WriteLine("sendMessageToClient received: " + info));
                hubConnection.Start();

                Console.WriteLine("Client started - hit Enter to send a message - ESC to stop");

                Console.ReadKey();

                while (true)
                {
                    var keyInfo = Console.ReadKey(true);

                    if (keyInfo.Key == ConsoleKey.Escape)
                        break;

                    var message = "Console client : " + DateTime.Now.ToString("HH:mm:ss-fff");
                    hubProxy.Invoke("BroadcastMessageToAll", message);
                    Console.WriteLine("Client sent BroadcastMessageToAll: " + message);
                }

                Console.WriteLine("Client stopping");

                hubConnection.Stop();

                Console.WriteLine("Client stopped - enter any key start again");
                Console.ReadLine();
            }
        }
    }
}

【问题讨论】:

  • 我希望我能提供更多帮助,但我将您的服务器和客户端代码逐字复制到两个控制台应用程序项目中。安装必要的 NuGet 包后,我能够重新启动服务器应用程序,让客户端自动重新连接,然后继续发送和接收消息。
  • 我更新了重现的步骤,使其更加准确。您应该重新启动服务器控制台应用程序本身,但 SignalR 服务器应用程序本身。

标签: c# asp.net signalr owin


【解决方案1】:

SignalR 团队向我指出了解决方案: 默认情况下,SignalR 使用 GlobalHost,它是一个单例解析器。处理后,它永远不会回来。

在为中心创建配置时,您应该传递一个新的依赖解析器:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var hubConfiguration = new HubConfiguration {Resolver = new DefaultDependencyResolver()};
        app.MapSignalR(hubConfiguration);
    }
}

【讨论】:

    【解决方案2】:

    Stian 的回答很棒。但是如果需要使用 GlobalHost 中定义的静态方法,则需要将 Dependency resolver 分配给 GlobalHost。

    以下对我有用:

    public void Configuration(IAppBuilder app)
    {
        .... Other configurations ....
        GlobalHost.DependencyResolver = new DefaultDependencyResolver();
        app.MapSignalR();
    }
    

    我是这样定义中心上下文的:

    public sealed class RemoteAdminHub : Hub
    {
        #region Properties
    
        /// <summary>
        /// Gets the SignalR Hub context.
        /// </summary>
        public static IHubContext HubContext
        {
            get
            {
                return GlobalHost.ConnectionManager.GetHubContext<RemoteAdminHub>();
            }
        }
    
        #endregion
    }
    

    【讨论】:

      【解决方案3】:

      我有几个与 SignalR 类似的问题(不完全是在同一场景中)。

      该问题通常是在通信模型 request_from_server->client->response_to_server 引起的。当我尝试在接收过程中直接在客户端代码中调用 Invoke(向服务器发送响应)时,出现了奇怪的行为(无限等待、奇怪的副作用等)。

      解决方案是将进程分成两个线程。一种用于从服务器接收消息到本地 ConcurrentQueue。第二个线程从队列中获取消息,处理它们并将响应发送回服务器(通过调用)。现在 SignalR 可以正常工作了。

      这个问题可能是由于在接收过程完成之前尝试发送响应造成的。这在通常的客户端->服务器->客户端通信模型中不会发生。

      【讨论】:

        猜你喜欢
        • 2017-05-26
        • 2016-04-29
        • 2015-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多