Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR client is reconnected after Owin restart, but message is not published

Setup:

  1. SignalRServer console app: Microsoft.AspNet.SignalR.SelfHost v2.0.3
  2. SignalRClient console app: Microsoft.AspNet.SignalR.Client v2.0.3
  3. .NET 4.5.1

I do the following:

  1. Hit enter on client, a message is received at server and on client again
  2. Dispose the server by hitting any key in the server console
  3. Restart the server by hitting any key in the server console
  4. Client is reconnected
  5. Hit enter on client, message is received at server, but never reaches the client again

I expect the message to be received at the client again. I suspect it has something to do with the self-hosting, since I've tried to run the client against same hub in a web application running IIS with success.

Any ideas?

Update: if the server console process is killed and restarted, it is able to reconnect AND retrieve 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();
            }
        }
    }
}
like image 600
Stian Avatar asked May 20 '14 12:05

Stian


2 Answers

The SignalR team pointed me to the solution: By default SignalR uses GlobalHost, which is a singleton resolver. When disposed, it will never come back.

When creating the configuration for the hub, you should pass inn a new dependency resolver:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var hubConfiguration = new HubConfiguration {Resolver = new DefaultDependencyResolver()};
        app.MapSignalR(hubConfiguration);
    }
}
like image 108
Stian Avatar answered Sep 23 '22 10:09

Stian


Stian's answer is great. But if you need to use static methods defined in GlobalHost, you need to assign the 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 this way:

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
}
like image 29
Yang Zhang Avatar answered Sep 21 '22 10:09

Yang Zhang