SignalR客户端在Owin重新启动后重新连接,但消息未发布

本文关键字:消息 重新连接 客户端 Owin 重新启动 SignalR | 更新日期: 2023-09-27 18:04:26

设置:

  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();
            }
        }
    }
}

SignalR客户端在Owin重新启动后重新连接,但消息未发布

SignalR团队向我介绍了解决方案:默认情况下,SignalR使用GlobalHost,这是一个单例解析程序。一旦处置,它将永远不会回来。

在为集线器创建配置时,应该传入一个新的依赖解析程序:

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

Stian的回答很好。但是,如果需要使用在GlobalHost中定义的静态方法,则需要将依赖关系解析程序分配给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
}

我对SignalR有几个类似的问题(在同一个场景中不是很严重(。

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

解决方案是将进程划分为两个线程。一个用于接收从服务器到本地并发队列的消息。第二个线程从队列中获取消息,处理它们并将响应发送回服务器(通过Invoke(。现在SignalR按预期工作。

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