locked
Re-connect problems when Server/Hub restarts. RRS feed

  • Question

  • User827443224 posted

    I have configured a signalr HUB to run as part of my windows service.  The client establishes a connection just fine, but when the service restarts, the reconnecting and reconnected events fire, but only client to server communication is available.  I have tried to re-establish the whole connection in JS without success.   All the related code is shown below.

    What is working:

    1. Initial HUB startup. JS initialization. Good client to server and server to client communication.
    2. Move off the MVC signalr page and back on. JS Initialization. Good client to server and server to client communication.
    3. Service restarts.  JS indicates Reconnecting and Connected.  Good client to server communication only.

    What is not working.

    1. Service restarts.  JS indicates Reconnecting and Connected, but hubProxy.on server methods no longer get called.
    2. Triggering InitializeServer again causes Disconnected event to fire forever.  Connection does not re-establish correctly/completely. 

    What is the proper method order to re-establish the connection so that the hubProxy.on methods continue to work after the service restart? 

    Thanks,

    function GetServerUrl(callback, callbackData) {
    
    var actionUrl = rootUrl + "Module/GetServerUrl";
    $.ajax({
    url: actionUrl,
    type: "GET",
    cache: false,
    dataType: "text",
    async: false,
    error: function() { return ""; },
    success: function(url) {
    //alert("S" + url);
    }
    }).done(function(url) {
    callback(url, callbackData);
    });
    }
    
    var connection;
    var hubProxy;
    
    
    function OnModuleAction(sender) {
    var args = $(sender).data();
    connection.start().done(function () {
    hubProxy.invoke('onModuleAction', args.id, args.cmd);
    });
    }
    
    function InitializeServer(url) {
    connection = $.hubConnection(url, { useDefaultPath: false });
    hubProxy = connection.createHubProxy('serviceHostHub');
    
    hubProxy.on('onRefreshModules', function () {
    masterGrid.Refresh();
    });
    
    var actionUrl = rootUrl + "Module/OnServerAction";
    hubProxy.on('onServerAction', function (id, cmd, data) {
    $.ajax({
    method: "POST",
    url: actionUrl,
    data: { id: id, cmd: cmd, data: data },
    cache: false,
    //success: function () { alert("SUCCESS"); },
    error: function () { alert("ERROR"); }
    //complete: function () { alert("COMPLETE"); }
    });
    });
    
    connection.connectionSlow(function () {
    alert("Slow connection");
    });
    
    connection.reconnecting(function () {
    alert("Reconnecting");
    });
    
    connection.reconnected(function () {
    alert("Reconnected");
    });
    
    connection.disconnected(function () {
    setTimeout(function () {
    alert("Disconnected");
    connection.start(); 
    }, 5000);
    });
    
    connection.start().done();
    }
    $(function () {
    GetServerUrl(InitializeServer);
    });

    [HubName("serviceHostHub")]
        public class NetworkHub : Hub
        {
            private static readonly ConcurrentDictionary<string, object> Connections =
                new ConcurrentDictionary<string, object>();
    
            internal static void OnRefreshModules()
            {
                IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NetworkHub>();
                context.Clients.All.onRefreshModules();
            }
    
            internal static void OnServerAction(string id, string command, string data)
            {
                IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NetworkHub>();
                context.Clients.All.onServerAction(id, command, data);
            }
    
            private static WebConsoleAction _webConsoleAction;
    
            internal static void SetWebConsoleActionCallback(WebConsoleAction webConsoleAction)
            {
                _webConsoleAction = webConsoleAction;
            }
    
            public void OnModuleAction(string id, string command)
            {
                KLog.Debug("WebConsole module {0} command {1}.".FormatWith(id, command));
                if (_webConsoleAction != null)
                {
                    _webConsoleAction("interface." + id, command);
                }
            }
    
            public override Task OnConnected()
            {
                Connections.TryAdd(Context.ConnectionId, null);
                return base.OnConnected();
            }
    
            public override Task OnReconnected()
            {
                Connections.TryAdd(Context.ConnectionId, null);
                return base.OnReconnected();
            }
    
            public override Task OnDisconnected(bool stopCalled)
            {
                object value;
                Connections.TryRemove(Context.ConnectionId, out value);
                KLog.Debug("Client {0} ".FormatWith(Context.ConnectionId) +
                           (stopCalled ? "explicitly closed the connection." : "timed out."));
                return base.OnDisconnected(stopCalled);
            }
    
        }
    
    private void StartNetworkHub()
            {
                var config = Config.SystemConfiguration.NetworkManagementSettings;
                var url = DsaNetworkManagementConfiguration.AssembleWebConsoleUrl(config.SocketDataWebConsole, config.UseSsl);
                _signalR = WebApp.Start<NetworkHubStart>(url);
            }
    
    public class NetworkHubStart
        {
            public void Configuration(IAppBuilder app)
            {
                app.Map("/signalr", map =>
                {
                    map.UseCors(CorsOptions.AllowAll);
    
                    var hubConfiguration = new HubConfiguration
                    {
                        EnableJSONP = true,
                        EnableDetailedErrors = true
                    };
    
                    map.RunSignalR(hubConfiguration);
                });
            }
    
        }
    



    Friday, April 28, 2017 4:15 PM

All replies

  • User827443224 posted

    To clarify a bit, the win service is not restarted, but signalR is Disposed and NetworkHubStart is called again. Something about the existing connection is hanging around which is preventing even new clients from connecting up. 

    Monday, May 1, 2017 11:10 PM
  • User-1838255255 posted

    Hi thestorms,

    After read your description and code, I think your code can not enter the OnReconnected method(on server side),

    More details please follow the Hubs API Guide:

    https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/handling-connection-lifetime-events 

    thestorms

    public override Task OnConnected() { Connections.TryAdd(Context.ConnectionId, null); return base.OnConnected(); } public override Task OnReconnected() { Connections.TryAdd(Context.ConnectionId, null); return base.OnReconnected(); }

    About the OnReconnected method, I know if the service disconnect, when reconnect it, it will create the new Custom Client ID. So my suggestion is manually manage a Custom Client ID(assign ID and reuse it again) instead of using Connection ID, and send them to server in client’s Reconnected event.

    Best Regards,

    Eric Du

     
     

    Tuesday, May 2, 2017 9:45 AM
  • User827443224 posted

    Thank you for the reply. I don't see how managing the users can solve my re-connection problem, so I think I am not following what your saying.

    I modified the "SignalR Self-Host Sample" to mimic what my code is doing and uploaded it to OneDrive.  Hopefully you will be able to look at it.  The only difference between my code and the sample is my code is not using the generated proxy. 

    https://1drv.ms/u/s!AnefnfzQ-qsZhBquFF1rGmjvzhkT

    Bring up the sample and establish that all communication is working. Then hit return in the Console which will dispose the existing hub and establish a new one. The client triggers Reconnecting and Reconnected events, but the existing client or any new clients cannot establish a connection.

    What would need to be added to the JS reconnected event?

    Anytime I add a DependencyResolver to the Configuration to implement user management, no connections can be established.

    var idProvider = new CustomUserIdProvider();
    GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);

    Tuesday, May 2, 2017 5:29 PM