我已经在自托管进程(目前是WinForm主机)中成功运行SignalR . 客户端可以与他们的浏览器连接并完美交互 . 当我需要重新启动游戏领域而不完全杀死主机进程时,问题就出现了 . 在处理了WebApp.Start()返回的IDisposable之后,我重新加载所有业务数据并再次调用WebApp.Start() . 它似乎工作,没有例外或警告冒出来,但无论是否有新的浏览器窗口或选项卡,来自浏览器的客户端连接都会失败 . 我在javascript中启用了SignalR跟踪,并且还通过Fiddler捕获流量 . / negotiate调用有效,但随后对WebSockets的/ connect调用在5秒后超时,然后通过所有其他SignalR回退失败 . 如果我完全杀死主机进程并重新启动它,一切都很好 . 通过每次杀死整个过程手动重启是不可行的 . 我打开了服务器端日志记录,这是我看到的行为:

SignalR.Transports.TransportHeartBeat Information: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 is New.
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Information: 0 : Dispose(). Closing all connections
SignalR.Transports.WebSocketTransport Error: 0 : OnError(a9f279c9-9dcb-4cc2-806b-dd95e96561b4, System.Net.WebSockets.WebSocketException (0x80004005): An internal WebSocket error occurred. Please see the innerException, if present, for more details.  ---> System.Net.HttpListenerException (0x80004005): The I/O operation has been aborted because of either a thread exit or an application request
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.<ReadAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Net.WebSockets.WebSocketBase.WebSocketOperation.<Process>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__1.MoveNext()
   at System.Net.WebSockets.WebSocketBase.ThrowIfConvertibleException(String methodName, Exception exception, CancellationToken cancellationToken, Boolean aborted)
   at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNet.SignalR.WebSockets.WebSocketMessageReader.<ReadMessageAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNet.SignalR.WebSockets.WebSocketHandler.<ProcessWebSocketRequestAsync>d__e.MoveNext())
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Information: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 is New.
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 263abf1d-aa32-41aa-af16-d64c530cd001 exists. Closing previous connection.
SignalR.Transports.ServerSentEventsTransport Information: 0 : End(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : Cancel(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : DrainWrites(263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.ServerSentEventsTransport Information: 0 : CompleteRequest (263abf1d-aa32-41aa-af16-d64c530cd001)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection a9f279c9-9dcb-4cc2-806b-dd95e96561b4 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(a9f279c9-9dcb-4cc2-806b-dd95e96561b4)

注意在处理过程中会发生错误,然后它会进入这种状态,它会永久地为现有连接和新连接重复该模式 .

任何帮助赞赏 .

Update: 有人请求共享重启的代码 . 它's basically a long running process, so at the core of my engine I'有一个循环循环,直到我告诉它停止 .

protected void MainLoop()
{
    //load all data from the db
    using (Microsoft.Owin.Hosting.WebApp.Start(dbRealm.SignalRUrl))
    {
        while (!this.stopping)
        {
            try
            {
                this.ProcessFrame();
            }
            catch (Exception exc)
            {
                //todo: log error
                throw exc;
            }

            Thread.Sleep(1); //yield
        }
    }
    //cleanup/shut down stuff
}

这是通过以下代码在它自己的线程上运行:

public void Start()
{
    //threading/message stuffs
    if (!this.running)
    {
        this.running = true;
        ThreadStart ts = new ThreadStart(this.MainLoop);
        this.mainThread = new Thread(ts);
        this.mainThread.Start();
    }
    else
    {
        //message
    }
}

这是我的Startup类:

class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCors(CorsOptions.AllowAll);
        app.MapSignalR("/signalr", new HubConfiguration { EnableDetailedErrors = true, Resolver = new DefaultDependencyResolver() });
        app.RunSignalR();
    }
}

Update #2: 我可能在OP中不够清楚 . 除了使用Fiddler记录流量之外,我还在客户端启用了SignalR跟踪 . 这是浏览器中的输出:

[08:03:37] SignalR: Auto detected cross domain url.
[08:03:37] SignalR: Client subscribed to hub 'webmudhub'.
[08:03:37] SignalR: Negotiating with 'http://localhost:8080/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D'.
[08:03:37] SignalR: webSockets transport starting.
[08:03:37] SignalR: Connecting to websocket endpoint 'ws://localhost:8080/connect?transport=webSockets&clientProtocol=1.5&connectionToken=AQAAANCMnd8BFdERjHoAwE%2FCl%2BsBAAAAecyNVO0bfE6%2BclQisGhh8QAAAAACAAAAAAAQZgAAAAEAACAAAACo51RwDaqYAC1N2%2FkMiQkuFhbVLfrH%2FfJEfdz9TV9F7AAAAAAOgAAAAAIAACAAAADrjqx8pyEMjZ%2BCkUHeZJcdwXH2LaSe1Qlh9XA7fo84MTAAAAB7mClxFPbknblDmZ8a14Thoa6FcLY7%2BS6fJpAXpeO8AaB8y5n4iCD6DotnQH07UDNAAAAA9eV4FLk1hr83h8NDy%2BWwKvGF%2FGn%2F00AOmn%2BMEfvcS5fa2xO%2F0Vd1sjd6TpJdTpePmakv1uOjTekP6FFYXVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D&tid=0'.
[08:03:37] SignalR: Websocket opened.
[08:03:42] SignalR: webSockets transport timed out when trying to connect.
[08:03:42] SignalR: Closing the Websocket.
[08:03:42] SignalR: webSockets transport failed to connect. Attempting to fall back.
[08:03:42] SignalR: serverSentEvents transport starting.
[08:03:42] SignalR: Attempting to connect to SSE endpoint 'http://localhost:8080/connect?transport=serverSentEvents&clientProtocol=1.5…XVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D&tid=3'.
[08:03:42] SignalR: EventSource connected.
[08:03:47] SignalR: serverSentEvents transport timed out when trying to connect.
[08:03:47] SignalR: EventSource calling close().
[08:03:47] SignalR: serverSentEvents transport failed to connect. Attempting to fall back.
[08:03:47] SignalR: longPolling transport starting.
[08:03:48] SignalR: Opening long polling request to 'http://localhost:8080/connect?transport=longPolling&clientProtocol=1.5&conn…kP6FFYXVTU7g%3D%3D&connectionData=%5B%7B%22name%22%3A%22webmudhub%22%7D%5D'.
[08:03:52] SignalR: longPolling transport timed out when trying to connect.
[08:03:52] SignalR: Aborted xhr request.
[08:03:52] SignalR: longPolling transport failed to connect. Attempting to fall back.
[08:03:52] SignalR: Fallback transports exhausted.
[08:03:52] SignalR: Stopping connection.
[08:03:52] SignalR: Fired ajax abort async = true.

请注意,在第一次处理WebApp.Start()之后第二次调用WebApp.Start()后,这是在新的浏览器连接上的 brand new connection 上 . 感觉可能没有在SignalR中正确处理某些东西,导致某种残余物导致问题 .

这是另一个服务器端日志 . 我启动了服务器,停止了它(处理SignalR),然后重新启动它(进行新的WebApp.Start()调用) . 它应该在这一点上接受新的连接 . 相反,我看到了这个:

SignalR.Transports.TransportHeartBeat Information: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 is New.
SignalR.Transports.WebSocketTransport Information: 0 : CloseSocket(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : 92c4d8da-aeb5-4056-b274-625a83a366b1 is dead
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 exists. Closing previous connection.
SignalR.Transports.WebSocketTransport Information: 0 : End(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Verbose: 0 : Cancel(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Verbose: 0 : DrainWrites(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.WebSocketTransport Information: 0 : CompleteRequest (92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : Connection 92c4d8da-aeb5-4056-b274-625a83a366b1 exists. Closing previous connection.
SignalR.Transports.ServerSentEventsTransport Information: 0 : End(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : Cancel(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Verbose: 0 : DrainWrites(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.ServerSentEventsTransport Information: 0 : CompleteRequest (92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)
SignalR.Transports.TransportHeartBeat Verbose: 0 : KeepAlive(92c4d8da-aeb5-4056-b274-625a83a366b1)

我们再一次看到新的连接,然后5秒后由于某种原因调用CloseSocket(),也许是因为它认为它已经死了?

我基本上试图遵循这种模式:https://weblog.west-wind.com/posts/2013/Sep/04/SelfHosting-SignalR-in-a-Windows-Service

我知道这是一个Windows服务,我的是在WinForm应用程序中托管,所以也许这就是区别?我想知道Windows服务是否在每个启动服务的请求上创建一个新的AppDomain . 正如我所说,如果我完全杀死WinForm应用程序并重新启动它,一切都会再次运行 .

在我看来,我应该能够Dispose of SignalR,然后通过另一次调用WebApp.Start()来启动它,但第二次调用WebApp.Start不会出错,但它也没有正确接受任何新的传入连接 . 他们超时了 . 这显然是我的猜想,但也许是SignalR中的单例模式或类似模式在IDisposable实现中没有被正确处理?我选择WinForms来在开发期间轻松记录/通知每个领域各自的WinForm主机,因为我将在每台Windows服务器上运行多个实例(每个实例在其自己的端口上都有自己的SignalR实例) .