SignalR client reconnects after restarting Owin, but message is not published

Setup:

  • SignalRServer Console Application: Microsoft.AspNet.SignalR.SelfHost v2.0.3
  • SignalRClient Console Application: Microsoft.AspNet.SignalR.Client v2.0.3
  • .NET 4.5.1

I do the following:

  • Hit input on the client, the message is received on the server and on the client again
  • Remove the server by pressing any key on the server console.
  • Reboot the server by pressing any key on the server console.
  • Client reconnected
  • Hit the input on the client, the message is received on the server, but never reaches the client.

I expect the message to be received from the client again. I suspect this has something to do with self-service, as I tried to successfully launch a client with the same hub in a web application with IIS.

Any ideas?

Update: if the server console process has been killed and restarted, it can reconnect and receive messages again.

Server code

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

Client code

 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(); } } } } 
+6
source share
3 answers

The SignalR team pointed me to a solution: By default, SignalR uses GlobalHost, which is a singleton resolver. When he wants, he will never return.

When creating a hub configuration, you must pass the visitor a new dependent converter:

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

The steak answer is great. But if you need to use the static methods defined in GlobalHost, you need to assign a dependency resolver to GlobalHost.

The following works for me:

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

I defined the hub context as follows:

 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 } 
+1
source

I have several similar problems with SignalR (not in the same scenario).

The problem was usually caused in the request_from_server-> client-> response_to_server communication model. When I tried to invoke Invoke in the client code (to send a response to the server) directly in the receiving procedure, I got strange behavior (endless expectations, strange side effects, etc.).

The solution was to split the process into two threads. One for receiving messages from the server to the local ConcurrentQueue. The second thread extracts messages from the queue, processes them, and sends the responses back to the server (via Invoke). SignalR now works as expected.

This problem was probably caused by an attempt to send a response before the completion of the receive procedure. This does not happen in the normal client> server> client communication model.

0
source

Source: https://habr.com/ru/post/969577/


All Articles